From ce2b3084e77d36a54b4e57c1a97f68d90846ae7e Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 16 Mar 2016 10:43:49 -0700 Subject: [PATCH 1/9] Get stack traces in crash dumps working for Windows --- test/core/util/test_config.c | 127 ++++++++++++++++++++++++++++++++--- 1 file changed, 117 insertions(+), 10 deletions(-) diff --git a/test/core/util/test_config.c b/test/core/util/test_config.c index 14bfc957cbd..83bbc0f4c4c 100644 --- a/test/core/util/test_config.c +++ b/test/core/util/test_config.c @@ -38,6 +38,8 @@ #include "src/core/support/string.h" #include #include +#include +#include double g_fixture_slowdown_factor = 1.0; @@ -52,14 +54,115 @@ static unsigned seed(void) { return _getpid(); } #endif #if GPR_WINDOWS_CRASH_HANDLER -LONG crash_handler(struct _EXCEPTION_POINTERS *ex_info) { - gpr_log(GPR_DEBUG, "Exception handler called, dumping information"); - while (ex_info->ExceptionRecord) { - DWORD code = ex_info->ExceptionRecord->ExceptionCode; - DWORD flgs = ex_info->ExceptionRecord->ExceptionFlags; - PVOID addr = ex_info->ExceptionRecord->ExceptionAddress; - gpr_log("code: %x - flags: %d - address: %p", code, flgs, addr); - ex_info->ExceptionRecord = ex_info->ExceptionRecord->ExceptionRecord; +#include "DbgHelp.h" + +#pragma comment(lib, "dbghelp.lib") + +static void print_current_stack() { + typedef USHORT(WINAPI *CaptureStackBackTraceType)(__in ULONG, __in ULONG, __out PVOID*, __out_opt PULONG); + CaptureStackBackTraceType func = (CaptureStackBackTraceType)(GetProcAddress(LoadLibrary(L"kernel32.dll"), "RtlCaptureStackBackTrace")); + + if (func == NULL) + return; // WOE 29.SEP.2010 + + // Quote from Microsoft Documentation: + // ## Windows Server 2003 and Windows XP: + // ## The sum of the FramesToSkip and FramesToCapture parameters must be less than 63. +#define MAX_CALLERS 62 + + void * callers_stack[MAX_CALLERS]; + unsigned short frames; + SYMBOL_INFOW * symbol; + HANDLE process; + process = GetCurrentProcess(); + SymInitialize(process, NULL, TRUE); + frames = (func)(0, MAX_CALLERS, callers_stack, NULL); + symbol = (SYMBOL_INFOW *)calloc(sizeof(SYMBOL_INFOW) + 256 * sizeof(char), 1); + symbol->MaxNameLen = 255; + symbol->SizeOfStruct = sizeof(SYMBOL_INFOW); + + const unsigned short MAX_CALLERS_SHOWN = 32; + frames = frames < MAX_CALLERS_SHOWN ? frames : MAX_CALLERS_SHOWN; + for (unsigned int i = 0; i < frames; i++) { + SymFromAddrW(process, (DWORD64)(callers_stack[i]), 0, symbol); + fwprintf(stderr, L"*** %d: %016I64LX %ls - 0x%0X\n", i, (DWORD64)callers_stack[i], symbol->Name, symbol->Address); + } + + free(symbol); +} + +static void print_stack_from_context(CONTEXT c) { + STACKFRAME s; // in/out stackframe + memset(&s, 0, sizeof(s)); + DWORD imageType; +#ifdef _M_IX86 + // normally, call ImageNtHeader() and use machine info from PE header + imageType = IMAGE_FILE_MACHINE_I386; + s.AddrPC.Offset = c.Eip; + s.AddrPC.Mode = AddrModeFlat; + s.AddrFrame.Offset = c.Ebp; + s.AddrFrame.Mode = AddrModeFlat; + s.AddrStack.Offset = c.Esp; + s.AddrStack.Mode = AddrModeFlat; +#elif _M_X64 + imageType = IMAGE_FILE_MACHINE_AMD64; + s.AddrPC.Offset = c.Rip; + s.AddrPC.Mode = AddrModeFlat; + s.AddrFrame.Offset = c.Rsp; + s.AddrFrame.Mode = AddrModeFlat; + s.AddrStack.Offset = c.Rsp; + s.AddrStack.Mode = AddrModeFlat; +#elif _M_IA64 + imageType = IMAGE_FILE_MACHINE_IA64; + s.AddrPC.Offset = c.StIIP; + s.AddrPC.Mode = AddrModeFlat; + s.AddrFrame.Offset = c.IntSp; + s.AddrFrame.Mode = AddrModeFlat; + s.AddrBStore.Offset = c.RsBSP; + s.AddrBStore.Mode = AddrModeFlat; + s.AddrStack.Offset = c.IntSp; + s.AddrStack.Mode = AddrModeFlat; +#else +#error "Platform not supported!" +#endif + + HANDLE process = GetCurrentProcess(); + HANDLE thread = GetCurrentThread(); + + SYMBOL_INFOW *symbol = (SYMBOL_INFOW *)calloc(sizeof(SYMBOL_INFOW) + 256 * sizeof(char), 1); + symbol->MaxNameLen = 255; + symbol->SizeOfStruct = sizeof(SYMBOL_INFOW); + + while (StackWalk(imageType, + process, + thread, + &s, + &c, + 0, + SymFunctionTableAccess, + SymGetModuleBase, + 0)) { + BOOL has_symbol = SymFromAddrW(process, (DWORD64)(s.AddrPC.Offset), 0, symbol); + fwprintf(stderr, L"*** %016I64LX %ls - 0x%0X\n", (DWORD64)(s.AddrPC.Offset), has_symbol ? symbol->Name : L"<>", symbol->Address); + } + + free(symbol); +} + +static LONG crash_handler(struct _EXCEPTION_POINTERS *ex_info) { + fprintf(stderr, "Exception handler called, dumping information\n"); + bool try_to_print_stack = true; + PEXCEPTION_RECORD exrec = ex_info->ExceptionRecord; + while (exrec) { + DWORD code = exrec->ExceptionCode; + DWORD flgs = exrec->ExceptionFlags; + PVOID addr = exrec->ExceptionAddress; + if (code == EXCEPTION_STACK_OVERFLOW) try_to_print_stack = false; + fprintf(stderr, "code: %x - flags: %d - address: %p\n", code, flgs, addr); + exrec = exrec->ExceptionRecord; + } + if (try_to_print_stack) { + print_stack_from_context(*ex_info->ContextRecord); } if (IsDebuggerPresent()) { __debugbreak(); @@ -69,8 +172,9 @@ LONG crash_handler(struct _EXCEPTION_POINTERS *ex_info) { return EXCEPTION_EXECUTE_HANDLER; } -void abort_handler(int sig) { - gpr_log(GPR_DEBUG, "Abort handler called."); +static void abort_handler(int sig) { + fprintf(stderr, "Abort handler called."); + print_current_stack(NULL); if (IsDebuggerPresent()) { __debugbreak(); } else { @@ -79,6 +183,9 @@ void abort_handler(int sig) { } static void install_crash_handler() { + if (!SymInitialize(GetCurrentProcess(), NULL, TRUE)) { + fprintf(stderr, "SymInitialize failed: %d", GetLastError()); + } SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)crash_handler); _set_abort_behavior(0, _WRITE_ABORT_MSG); _set_abort_behavior(0, _CALL_REPORTFAULT); From 2b45cb827f0a65a84c5577a11f7d9572446124d8 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 16 Mar 2016 10:44:57 -0700 Subject: [PATCH 2/9] clang-format code --- test/core/util/test_config.c | 49 ++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/test/core/util/test_config.c b/test/core/util/test_config.c index 83bbc0f4c4c..554c6530728 100644 --- a/test/core/util/test_config.c +++ b/test/core/util/test_config.c @@ -59,21 +59,23 @@ static unsigned seed(void) { return _getpid(); } #pragma comment(lib, "dbghelp.lib") static void print_current_stack() { - typedef USHORT(WINAPI *CaptureStackBackTraceType)(__in ULONG, __in ULONG, __out PVOID*, __out_opt PULONG); - CaptureStackBackTraceType func = (CaptureStackBackTraceType)(GetProcAddress(LoadLibrary(L"kernel32.dll"), "RtlCaptureStackBackTrace")); + typedef USHORT(WINAPI * CaptureStackBackTraceType)( + __in ULONG, __in ULONG, __out PVOID *, __out_opt PULONG); + CaptureStackBackTraceType func = (CaptureStackBackTraceType)( + GetProcAddress(LoadLibrary(L"kernel32.dll"), "RtlCaptureStackBackTrace")); - if (func == NULL) - return; // WOE 29.SEP.2010 + if (func == NULL) return; // WOE 29.SEP.2010 - // Quote from Microsoft Documentation: - // ## Windows Server 2003 and Windows XP: - // ## The sum of the FramesToSkip and FramesToCapture parameters must be less than 63. +// Quote from Microsoft Documentation: +// ## Windows Server 2003 and Windows XP: +// ## The sum of the FramesToSkip and FramesToCapture parameters must be less +// than 63. #define MAX_CALLERS 62 - void * callers_stack[MAX_CALLERS]; + void *callers_stack[MAX_CALLERS]; unsigned short frames; - SYMBOL_INFOW * symbol; - HANDLE process; + SYMBOL_INFOW *symbol; + HANDLE process; process = GetCurrentProcess(); SymInitialize(process, NULL, TRUE); frames = (func)(0, MAX_CALLERS, callers_stack, NULL); @@ -81,18 +83,19 @@ static void print_current_stack() { symbol->MaxNameLen = 255; symbol->SizeOfStruct = sizeof(SYMBOL_INFOW); - const unsigned short MAX_CALLERS_SHOWN = 32; + const unsigned short MAX_CALLERS_SHOWN = 32; frames = frames < MAX_CALLERS_SHOWN ? frames : MAX_CALLERS_SHOWN; for (unsigned int i = 0; i < frames; i++) { SymFromAddrW(process, (DWORD64)(callers_stack[i]), 0, symbol); - fwprintf(stderr, L"*** %d: %016I64LX %ls - 0x%0X\n", i, (DWORD64)callers_stack[i], symbol->Name, symbol->Address); + fwprintf(stderr, L"*** %d: %016I64LX %ls - 0x%0X\n", i, + (DWORD64)callers_stack[i], symbol->Name, symbol->Address); } free(symbol); } static void print_stack_from_context(CONTEXT c) { - STACKFRAME s; // in/out stackframe + STACKFRAME s; // in/out stackframe memset(&s, 0, sizeof(s)); DWORD imageType; #ifdef _M_IX86 @@ -129,21 +132,17 @@ static void print_stack_from_context(CONTEXT c) { HANDLE process = GetCurrentProcess(); HANDLE thread = GetCurrentThread(); - SYMBOL_INFOW *symbol = (SYMBOL_INFOW *)calloc(sizeof(SYMBOL_INFOW) + 256 * sizeof(char), 1); + SYMBOL_INFOW *symbol = + (SYMBOL_INFOW *)calloc(sizeof(SYMBOL_INFOW) + 256 * sizeof(char), 1); symbol->MaxNameLen = 255; symbol->SizeOfStruct = sizeof(SYMBOL_INFOW); - while (StackWalk(imageType, - process, - thread, - &s, - &c, - 0, - SymFunctionTableAccess, - SymGetModuleBase, - 0)) { - BOOL has_symbol = SymFromAddrW(process, (DWORD64)(s.AddrPC.Offset), 0, symbol); - fwprintf(stderr, L"*** %016I64LX %ls - 0x%0X\n", (DWORD64)(s.AddrPC.Offset), has_symbol ? symbol->Name : L"<>", symbol->Address); + while (StackWalk(imageType, process, thread, &s, &c, 0, + SymFunctionTableAccess, SymGetModuleBase, 0)) { + BOOL has_symbol = + SymFromAddrW(process, (DWORD64)(s.AddrPC.Offset), 0, symbol); + fwprintf(stderr, L"*** %016I64LX %ls - 0x%0X\n", (DWORD64)(s.AddrPC.Offset), + has_symbol ? symbol->Name : L"<>", symbol->Address); } free(symbol); From 3c788053bc86020a59eae45f538551f325422494 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 16 Mar 2016 10:45:32 -0700 Subject: [PATCH 3/9] Fix copyright --- test/core/util/test_config.c | 2 +- third_party/boringssl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/core/util/test_config.c b/test/core/util/test_config.c index 554c6530728..94ef1be6ce3 100644 --- a/test/core/util/test_config.c +++ b/test/core/util/test_config.c @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/third_party/boringssl b/third_party/boringssl index 9f897b25800..907ae62b9d8 160000 --- a/third_party/boringssl +++ b/third_party/boringssl @@ -1 +1 @@ -Subproject commit 9f897b25800d2f54f5c442ef01a60721aeca6d87 +Subproject commit 907ae62b9d81121cb86b604f83e6b811a43f7a87 From ae2283d3dd504d796b8f846da077dc22b097ef4e Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 16 Mar 2016 10:53:58 -0700 Subject: [PATCH 4/9] Bleh --- third_party/boringssl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/boringssl b/third_party/boringssl index 907ae62b9d8..9f897b25800 160000 --- a/third_party/boringssl +++ b/third_party/boringssl @@ -1 +1 @@ -Subproject commit 907ae62b9d81121cb86b604f83e6b811a43f7a87 +Subproject commit 9f897b25800d2f54f5c442ef01a60721aeca6d87 From c9c0b8bf42e2fe41ff55318eb45d2716bcf0fc68 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 16 Mar 2016 14:57:29 -0700 Subject: [PATCH 5/9] Review feedback --- test/core/util/test_config.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/test/core/util/test_config.c b/test/core/util/test_config.c index 94ef1be6ce3..ede9118ac57 100644 --- a/test/core/util/test_config.c +++ b/test/core/util/test_config.c @@ -54,15 +54,20 @@ static unsigned seed(void) { return _getpid(); } #endif #if GPR_WINDOWS_CRASH_HANDLER -#include "DbgHelp.h" +#include +#include +#define DBGHELP_TRANSLATE_TCHAR +#include +#ifdef _MSC_VER #pragma comment(lib, "dbghelp.lib") +#endif static void print_current_stack() { typedef USHORT(WINAPI * CaptureStackBackTraceType)( __in ULONG, __in ULONG, __out PVOID *, __out_opt PULONG); CaptureStackBackTraceType func = (CaptureStackBackTraceType)( - GetProcAddress(LoadLibrary(L"kernel32.dll"), "RtlCaptureStackBackTrace")); + GetProcAddress(LoadLibrary(_T("kernel32.dll")), "RtlCaptureStackBackTrace")); if (func == NULL) return; // WOE 29.SEP.2010 @@ -79,7 +84,7 @@ static void print_current_stack() { process = GetCurrentProcess(); SymInitialize(process, NULL, TRUE); frames = (func)(0, MAX_CALLERS, callers_stack, NULL); - symbol = (SYMBOL_INFOW *)calloc(sizeof(SYMBOL_INFOW) + 256 * sizeof(char), 1); + symbol = (SYMBOL_INFOW *)calloc(sizeof(SYMBOL_INFOW) + 256 * sizeof(wchar_t), 1); symbol->MaxNameLen = 255; symbol->SizeOfStruct = sizeof(SYMBOL_INFOW); @@ -133,7 +138,7 @@ static void print_stack_from_context(CONTEXT c) { HANDLE thread = GetCurrentThread(); SYMBOL_INFOW *symbol = - (SYMBOL_INFOW *)calloc(sizeof(SYMBOL_INFOW) + 256 * sizeof(char), 1); + (SYMBOL_INFOW *)calloc(sizeof(SYMBOL_INFOW) + 256 * sizeof(wchar_t), 1); symbol->MaxNameLen = 255; symbol->SizeOfStruct = sizeof(SYMBOL_INFOW); From adf3a9d0b06359f07a22a5b2d37638c7f9a4ad02 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 16 Mar 2016 14:59:36 -0700 Subject: [PATCH 6/9] clang-fmt --- test/core/util/test_config.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/core/util/test_config.c b/test/core/util/test_config.c index ede9118ac57..15ba78413c3 100644 --- a/test/core/util/test_config.c +++ b/test/core/util/test_config.c @@ -66,8 +66,8 @@ static unsigned seed(void) { return _getpid(); } static void print_current_stack() { typedef USHORT(WINAPI * CaptureStackBackTraceType)( __in ULONG, __in ULONG, __out PVOID *, __out_opt PULONG); - CaptureStackBackTraceType func = (CaptureStackBackTraceType)( - GetProcAddress(LoadLibrary(_T("kernel32.dll")), "RtlCaptureStackBackTrace")); + CaptureStackBackTraceType func = (CaptureStackBackTraceType)(GetProcAddress( + LoadLibrary(_T("kernel32.dll")), "RtlCaptureStackBackTrace")); if (func == NULL) return; // WOE 29.SEP.2010 @@ -84,7 +84,8 @@ static void print_current_stack() { process = GetCurrentProcess(); SymInitialize(process, NULL, TRUE); frames = (func)(0, MAX_CALLERS, callers_stack, NULL); - symbol = (SYMBOL_INFOW *)calloc(sizeof(SYMBOL_INFOW) + 256 * sizeof(wchar_t), 1); + symbol = + (SYMBOL_INFOW *)calloc(sizeof(SYMBOL_INFOW) + 256 * sizeof(wchar_t), 1); symbol->MaxNameLen = 255; symbol->SizeOfStruct = sizeof(SYMBOL_INFOW); From 2befb68e82f81c15e06eff637de884ba76f48e20 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 16 Mar 2016 17:16:02 -0700 Subject: [PATCH 7/9] Tweaking formatting --- test/core/util/test_config.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/test/core/util/test_config.c b/test/core/util/test_config.c index 15ba78413c3..5d4f659fb1f 100644 --- a/test/core/util/test_config.c +++ b/test/core/util/test_config.c @@ -33,13 +33,13 @@ #include "test/core/util/test_config.h" -#include #include -#include "src/core/support/string.h" -#include +#include #include -#include #include +#include +#include +#include "src/core/support/string.h" double g_fixture_slowdown_factor = 1.0; @@ -54,8 +54,8 @@ static unsigned seed(void) { return _getpid(); } #endif #if GPR_WINDOWS_CRASH_HANDLER -#include #include +#include #define DBGHELP_TRANSLATE_TCHAR #include @@ -93,8 +93,8 @@ static void print_current_stack() { frames = frames < MAX_CALLERS_SHOWN ? frames : MAX_CALLERS_SHOWN; for (unsigned int i = 0; i < frames; i++) { SymFromAddrW(process, (DWORD64)(callers_stack[i]), 0, symbol); - fwprintf(stderr, L"*** %d: %016I64LX %ls - 0x%0X\n", i, - (DWORD64)callers_stack[i], symbol->Name, symbol->Address); + fwprintf(stderr, L"*** %d: %016I64LX %ls - %016I64LX\n", i, + (DWORD64)callers_stack[i], symbol->Name, (DWORD64)symbol->Address); } free(symbol); @@ -147,8 +147,9 @@ static void print_stack_from_context(CONTEXT c) { SymFunctionTableAccess, SymGetModuleBase, 0)) { BOOL has_symbol = SymFromAddrW(process, (DWORD64)(s.AddrPC.Offset), 0, symbol); - fwprintf(stderr, L"*** %016I64LX %ls - 0x%0X\n", (DWORD64)(s.AddrPC.Offset), - has_symbol ? symbol->Name : L"<>", symbol->Address); + fwprintf( + stderr, L"*** %016I64LX %ls - %016I64LX\n", (DWORD64)(s.AddrPC.Offset), + has_symbol ? symbol->Name : L"<>", (DWORD64)symbol->Address); } free(symbol); @@ -178,7 +179,7 @@ static LONG crash_handler(struct _EXCEPTION_POINTERS *ex_info) { } static void abort_handler(int sig) { - fprintf(stderr, "Abort handler called."); + fprintf(stderr, "Abort handler called.\n"); print_current_stack(NULL); if (IsDebuggerPresent()) { __debugbreak(); @@ -189,7 +190,7 @@ static void abort_handler(int sig) { static void install_crash_handler() { if (!SymInitialize(GetCurrentProcess(), NULL, TRUE)) { - fprintf(stderr, "SymInitialize failed: %d", GetLastError()); + fprintf(stderr, "SymInitialize failed: %d\n", GetLastError()); } SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)crash_handler); _set_abort_behavior(0, _WRITE_ABORT_MSG); @@ -197,11 +198,11 @@ static void install_crash_handler() { signal(SIGABRT, abort_handler); } #elif GPR_POSIX_CRASH_HANDLER +#include #include +#include #include #include -#include -#include static char g_alt_stack[MINSIGSTKSZ]; From b195792ed92dbed8b7226cb1311eaccd12afab07 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 16 Mar 2016 17:22:57 -0700 Subject: [PATCH 8/9] Drop the L --- test/core/util/test_config.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/core/util/test_config.c b/test/core/util/test_config.c index 5d4f659fb1f..bd3c50d7367 100644 --- a/test/core/util/test_config.c +++ b/test/core/util/test_config.c @@ -54,8 +54,10 @@ static unsigned seed(void) { return _getpid(); } #endif #if GPR_WINDOWS_CRASH_HANDLER -#include #include + +#include + #define DBGHELP_TRANSLATE_TCHAR #include @@ -93,7 +95,7 @@ static void print_current_stack() { frames = frames < MAX_CALLERS_SHOWN ? frames : MAX_CALLERS_SHOWN; for (unsigned int i = 0; i < frames; i++) { SymFromAddrW(process, (DWORD64)(callers_stack[i]), 0, symbol); - fwprintf(stderr, L"*** %d: %016I64LX %ls - %016I64LX\n", i, + fwprintf(stderr, L"*** %d: %016I64X %ls - %016I64X\n", i, (DWORD64)callers_stack[i], symbol->Name, (DWORD64)symbol->Address); } @@ -148,7 +150,7 @@ static void print_stack_from_context(CONTEXT c) { BOOL has_symbol = SymFromAddrW(process, (DWORD64)(s.AddrPC.Offset), 0, symbol); fwprintf( - stderr, L"*** %016I64LX %ls - %016I64LX\n", (DWORD64)(s.AddrPC.Offset), + stderr, L"*** %016I64X %ls - %016I64X\n", (DWORD64)(s.AddrPC.Offset), has_symbol ? symbol->Name : L"<>", (DWORD64)symbol->Address); } From 2ed1a9e32960c7ff60db41859c9a5b8f55867db7 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 16 Mar 2016 20:09:43 -0700 Subject: [PATCH 9/9] Disable warning: system header is broken --- test/core/util/test_config.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/core/util/test_config.c b/test/core/util/test_config.c index bd3c50d7367..bf672e8f677 100644 --- a/test/core/util/test_config.c +++ b/test/core/util/test_config.c @@ -58,6 +58,8 @@ static unsigned seed(void) { return _getpid(); } #include +// disable warning 4091 - dbghelp.h is broken for msvc2015 +#pragma warning(disable : 4091) #define DBGHELP_TRANSLATE_TCHAR #include