--- include/ruby/win32.h | 3 + vm_dump.c | 2 + win32/win32.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 0 deletions(-) diff --git a/include/ruby/win32.h b/include/ruby/win32.h index 7b6bded..db646b2 100644 --- a/include/ruby/win32.h +++ b/include/ruby/win32.h @@ -672,6 +672,9 @@ in asynchronous_func_t. typedef uintptr_t (*asynchronous_func_t)(uintptr_t self, int argc, uintptr_t* argv); uintptr_t rb_w32_asynchronize(asynchronous_func_t func, uintptr_t self, int argc, uintptr_t* argv, uintptr_t intrval); +/* backtrace */ +void rb_w32_backtrace(); + #if defined __GNUC__ && __GNUC__ >= 4 #pragma GCC visibility pop #endif diff --git a/vm_dump.c b/vm_dump.c index f245ccc..c0199b1 100644 --- a/vm_dump.c +++ b/vm_dump.c @@ -616,5 +616,7 @@ rb_vm_bugreport(void) } fprintf(stderr, "\n"); } +#elif _WIN32 + rb_w32_backtrace(); #endif } diff --git a/win32/win32.c b/win32/win32.c index 46cdafa..b9d9713 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -36,6 +36,9 @@ #ifdef __MINGW32__ #include #endif +#if _MSC_VER && _M_IX86 +#include +#endif #include "ruby/win32.h" #include "win32/dir.h" #define isdirsep(x) ((x) == '/' || (x) == '\\') @@ -5694,3 +5697,108 @@ signbit(double x) return *ip < 0; } #endif + +#if _MSC_VER && _M_IX86 +static struct DumpArgs { + DWORD thread_id; + HANDLE event; +}; + +static void +dump_thread(void *arg) +{ + struct DumpArgs* dump_args = (struct DumpArgs*)arg; + HANDLE process = GetCurrentProcess(); + HANDLE thread = OpenThread(THREAD_ALL_ACCESS, 0, dump_args->thread_id); + STACKFRAME64 stackFrame; + CONTEXT context; + BOOL bool_rc; + DWORD64 dwDisplacement; + DWORD64 dwAddress; + char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; + PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; + IMAGEHLP_LINE64 line; + DWORD dwLineDisplacement; + + SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES); + + if (!SymInitialize(process, NULL, TRUE)) abort(); + + memset(&context, 0, sizeof(CONTEXT)); + context.ContextFlags = CONTEXT_FULL; + bool_rc = GetThreadContext(thread, &context); + if(!bool_rc) abort(); + + memset(&stackFrame,0,sizeof(STACKFRAME64)); + stackFrame.AddrPC.Mode = AddrModeFlat; + stackFrame.AddrPC.Offset = context.Eip; + + stackFrame.AddrFrame.Mode = AddrModeFlat; + stackFrame.AddrFrame.Offset = context.Ebp; + + stackFrame.AddrStack.Mode = AddrModeFlat; + stackFrame.AddrStack.Offset = context.Esp; + + fprintf(stderr, "-- C level backtrace information " + "-------------------------------------------\n"); + + while(1) + { + bool_rc = StackWalk64( + IMAGE_FILE_MACHINE_I386, + process, + thread, + &stackFrame, + (PVOID)&context, + NULL, + SymFunctionTableAccess64, + SymGetModuleBase64, + NULL); + if(!bool_rc) break; + + dwDisplacement = 0; + dwAddress = stackFrame.AddrPC.Offset; + + memset(buffer, 0, sizeof(buffer)); + pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); + pSymbol->MaxNameLen = MAX_SYM_NAME; + + if (SymFromAddr(process, dwAddress, &dwDisplacement, pSymbol)) + { + fprintf(stderr, "(%s)", pSymbol->Name); + } + + memset(&line, 0, sizeof(IMAGEHLP_LINE64)); + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + + if (SymGetLineFromAddr64(process, dwAddress, &dwLineDisplacement, &line)) + { + fprintf(stderr, "(%s:%lu)", line.FileName, line.LineNumber); + } + + fprintf(stderr, " [0x%08I64x]\n", dwAddress); + } + fprintf(stderr, "\n"); + + if (!CloseHandle(thread)) abort(); + if (!SymCleanup(process)) abort(); + if (!SetEvent(dump_args->event)) abort(); +} + +void +rb_w32_backtrace() { + struct DumpArgs dump_args; + dump_args.thread_id = GetCurrentThreadId(); + dump_args.event = CreateEvent(NULL, TRUE, FALSE, NULL); + if(!dump_args.event) abort(); + _beginthread(dump_thread,0,&dump_args); + + if (WaitForSingleObject(dump_args.event, INFINITE) != WAIT_OBJECT_0) abort(); +} +#elif +void +rb_w32_backtrace() { +} +#endif + + --