summaryrefslogtreecommitdiff
path: root/vm_dump.c
diff options
context:
space:
mode:
authorusa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-09-28 11:08:56 +0000
committerusa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-09-28 11:08:56 +0000
commit340997aec7f80aaf489e53b7c4f59b9567016334 (patch)
tree36df798640eafa2b8eb7b5ff4e504c86cd8160cc /vm_dump.c
parent86a8b820d636a36ddc49f9c906f5d0744dd3ef23 (diff)
* 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
Diffstat (limited to 'vm_dump.c')
-rw-r--r--vm_dump.c194
1 files changed, 189 insertions, 5 deletions
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 <execinfo.h>
+# include <execinfo.h>
+#elif defined(_WIN32)
+# include <imagehlp.h>
+# 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<n; i++) {
fprintf(stderr, "%s\n", syms[i]);
}
free(syms);
}
- fprintf(stderr, "\n");
+#elif defined(_WIN32)
+ DWORD tid = GetCurrentThreadId();
+ HANDLE th = (HANDLE)_beginthread(dump_thread, 0, &tid);
+ if (th != (HANDLE)-1)
+ WaitForSingleObject(th, INFINITE);
+#endif
}
+
+ fprintf(stderr, "\n");
#endif
}