From 340997aec7f80aaf489e53b7c4f59b9567016334 Mon Sep 17 00:00:00 2001 From: usa Date: Tue, 28 Sep 2010 11:08:56 +0000 Subject: * vm_dump.c (rb_vm_bugreport): add windows support. based on patchs from Peter Weldon at [ruby-core:32551] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@29352 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- vm_dump.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 189 insertions(+), 5 deletions(-) (limited to 'vm_dump.c') diff --git a/vm_dump.c b/vm_dump.c index f245cccca0..48a1169c33 100644 --- a/vm_dump.c +++ b/vm_dump.c @@ -584,8 +584,183 @@ bugreport_backtrace(void *arg, VALUE file, int line, VALUE method) } #if HAVE_BACKTRACE -#include +# include +#elif defined(_WIN32) +# include +# ifndef SYMOPT_DEBUG +# define SYMOPT_DEBUG 0x80000000 +# endif +# ifndef MAX_SYM_NAME +# define MAX_SYM_NAME 2000 +typedef struct { + DWORD64 Offset; + WORD Segment; + ADDRESS_MODE Mode; +} ADDRESS64; +typedef struct { + DWORD64 Thread; + DWORD ThCallbackStack; + DWORD ThCallbackBStore; + DWORD NextCallback; + DWORD FramePointer; + DWORD64 KiCallUserMode; + DWORD64 KeUserCallbackDispatcher; + DWORD64 SystemRangeStart; + DWORD64 KiUserExceptionDispatcher; + DWORD64 StackBase; + DWORD64 StackLimit; + DWORD64 Reserved[5]; +} KDHELP64; +typedef struct { + ADDRESS64 AddrPC; + ADDRESS64 AddrReturn; + ADDRESS64 AddrFrame; + ADDRESS64 AddrStack; + ADDRESS64 AddrBStore; + void *FuncTableEntry; + DWORD64 Params[4]; + BOOL Far; + BOOL Virtual; + DWORD64 Reserved[3]; + KDHELP64 KdHelp; +} STACKFRAME64; +typedef struct { + ULONG SizeOfStruct; + ULONG TypeIndex; + ULONG64 Reserved[2]; + ULONG Index; + ULONG Size; + ULONG64 ModBase; + ULONG Flags; + ULONG64 Value; + ULONG64 Address; + ULONG Register; + ULONG Scope; + ULONG Tag; + ULONG NameLen; + ULONG MaxNameLen; + char Name[1]; +} SYMBOL_INFO; +typedef struct { + DWORD SizeOfStruct; + void *Key; + DWORD LineNumber; + char *FileName; + DWORD64 Address; +} IMAGEHLP_LINE64; +typedef void *PREAD_PROCESS_MEMORY_ROUTINE64; +typedef void *PFUNCTION_TABLE_ACCESS_ROUTINE64; +typedef void *PGET_MODULE_BASE_ROUTINE64; +typedef void *PTRANSLATE_ADDRESS_ROUTINE64; +# endif + +static void +dump_thread(void *arg) +{ + HANDLE dbghelp; + BOOL (WINAPI *pSymInitialize)(HANDLE, const char *, BOOL); + BOOL (WINAPI *pSymCleanup)(HANDLE); + BOOL (WINAPI *pStackWalk64)(DWORD, HANDLE, HANDLE, STACKFRAME64 *, void *, PREAD_PROCESS_MEMORY_ROUTINE64, PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64); + BOOL (WINAPI *pSymGetModuleBase64)(HANDLE, DWORD64); + BOOL (WINAPI *pSymFromAddr)(HANDLE, DWORD64, DWORD64 *, SYMBOL_INFO *); + BOOL (WINAPI *pSymGetLineFromAddr64)(HANDLE, DWORD64, DWORD *, IMAGEHLP_LINE64 *); + HANDLE (WINAPI *pOpenThread)(DWORD, BOOL, DWORD); + DWORD tid = *(DWORD *)arg; + HANDLE ph; + HANDLE th; + + dbghelp = LoadLibrary("dbghelp.dll"); + if (!dbghelp) return; + pSymInitialize = (BOOL (WINAPI *)(HANDLE, const char *, BOOL))GetProcAddress(dbghelp, "SymInitialize"); + pSymCleanup = (BOOL (WINAPI *)(HANDLE))GetProcAddress(dbghelp, "SymCleanup"); + pStackWalk64 = (BOOL (WINAPI *)(DWORD, HANDLE, HANDLE, STACKFRAME64 *, void *, PREAD_PROCESS_MEMORY_ROUTINE64, PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64))GetProcAddress(dbghelp, "StackWalk64"); + pSymGetModuleBase64 = (BOOL (WINAPI *)(HANDLE, DWORD64))GetProcAddress(dbghelp, "SymGetModuleBase64"); + pSymFromAddr = (BOOL (WINAPI *)(HANDLE, DWORD64, DWORD64 *, SYMBOL_INFO *))GetProcAddress(dbghelp, "SymFromAddr"); + pSymGetLineFromAddr64 = (BOOL (WINAPI *)(HANDLE, DWORD64, DWORD *, IMAGEHLP_LINE64 *))GetProcAddress(dbghelp, "SymGetLineFromAddr64"); + pOpenThread = (HANDLE (WINAPI *)(DWORD, BOOL, DWORD))GetProcAddress(GetModuleHandle("kernel32.dll"), "OpenThread"); + if (pSymInitialize && pSymCleanup && pStackWalk64 && pSymGetModuleBase64 && + pSymFromAddr && pSymGetLineFromAddr64 && pOpenThread) { + SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES); + ph = GetCurrentProcess(); + pSymInitialize(ph, NULL, TRUE); + th = pOpenThread(THREAD_ALL_ACCESS, FALSE, tid); + if (th) { + if (SuspendThread(th) != (DWORD)-1) { + CONTEXT context; + memset(&context, 0, sizeof(context)); + context.ContextFlags = CONTEXT_FULL; + if (GetThreadContext(th, &context)) { + char libpath[MAX_PATH]; + char buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; + SYMBOL_INFO *info = (SYMBOL_INFO *)buf; + DWORD mac; + STACKFRAME64 frame; + memset(&frame, 0, sizeof(frame)); +#if defined(_M_AMD64) || defined(__x86_64__) + mac = IMAGE_FILE_MACHINE_AMD64; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrPC.Offset = context.Rip; + frame.AddrFrame.Mode = AddrModeFlat; + frame.AddrFrame.Offset = context.Rbp; + frame.AddrStack.Mode = AddrModeFlat; + frame.AddrStack.Offset = context.Rsp; +#elif defined(_M_IA64) || defined(__ia64__) + mac = IMAGE_FILE_MACHINE_IA64; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrPC.Offset = context.StIIP; + frame.AddrBStore.Mode = AddrModeFlat; + frame.AddrBStore.Offset = context.RsBSP; + frame.AddrStack.Mode = AddrModeFlat; + frame.AddrStack.Offset = context.IntSp; +#else /* i386 */ + mac = IMAGE_FILE_MACHINE_I386; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrPC.Offset = context.Eip; + frame.AddrFrame.Mode = AddrModeFlat; + frame.AddrFrame.Offset = context.Ebp; + frame.AddrStack.Mode = AddrModeFlat; + frame.AddrStack.Offset = context.Esp; +#endif + + while (pStackWalk64(mac, ph, th, &frame, &context, NULL, + NULL, NULL, NULL)) { + DWORD64 addr = frame.AddrPC.Offset; + DWORD64 displace64; + DWORD displace; + IMAGEHLP_LINE64 line; + + if (addr == frame.AddrReturn.Offset || + addr == 0 || frame.AddrReturn.Offset == 0) { + break; + } + + memset(buf, 0, sizeof(buf)); + info->SizeOfStruct = sizeof(SYMBOL_INFO); + info->MaxNameLen = MAX_SYM_NAME; + if (pSymFromAddr(ph, addr, &displace64, info)) { + if (GetModuleFileName((HANDLE)pSymGetModuleBase64(ph, addr), libpath, sizeof(libpath))) + fprintf(stderr, "%s", libpath); + fprintf(stderr, "(%s)", info->Name); + } + + memset(&line, 0, sizeof(line)); + line.SizeOfStruct = sizeof(line); + if (pSymGetLineFromAddr64(ph, addr, &displace, &line)) + fprintf(stderr, " %s:%lu", line.FileName, line.LineNumber); + fprintf(stderr, " [0x%"PRIxVALUE"]\n", addr); + } + } + + ResumeThread(th); + } + CloseHandle(th); + } + pSymCleanup(ph); + } + FreeLibrary(dbghelp); +} #endif + void rb_vm_bugreport(void) { @@ -598,23 +773,32 @@ rb_vm_bugreport(void) } } +#if HAVE_BACKTRACE || defined(_WIN32) + fprintf(stderr, "-- C level backtrace information " + "-------------------------------------------\n"); + + { #if HAVE_BACKTRACE #define MAX_NATIVE_TRACE 1024 - { static void *trace[MAX_NATIVE_TRACE]; int n = backtrace(trace, MAX_NATIVE_TRACE); char **syms = backtrace_symbols(trace, n); int i; - fprintf(stderr, "-- C level backtrace information " - "-------------------------------------------\n"); if (syms) { for (i=0; i