Feature #3875 » 0002-Add-C-level-backtrace-for-MSWIN-x86.patch
| include/ruby/win32.h | ||
|---|---|---|
|
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
|
||
| vm_dump.c | ||
|---|---|---|
|
}
|
||
|
fprintf(stderr, "\n");
|
||
|
}
|
||
|
#elif _WIN32
|
||
|
rb_w32_backtrace();
|
||
|
#endif
|
||
|
}
|
||
| win32/win32.c | ||
|---|---|---|
|
#ifdef __MINGW32__
|
||
|
#include <mswsock.h>
|
||
|
#endif
|
||
|
#if _MSC_VER && _M_IX86
|
||
|
#include <DbgHelp.h>
|
||
|
#endif
|
||
|
#include "ruby/win32.h"
|
||
|
#include "win32/dir.h"
|
||
|
#define isdirsep(x) ((x) == '/' || (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;
|
||
|
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;
|
||
|
if (!GetThreadContext(thread, &context)) 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 (StackWalk64(IMAGE_FILE_MACHINE_I386, process, thread, &stackFrame,
|
||
|
(PVOID)&context, NULL, SymFunctionTableAccess64,
|
||
|
SymGetModuleBase64, NULL)) {
|
||
|
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();
|
||
|
}
|
||
|
#else
|
||
|
void
|
||
|
rb_w32_backtrace() {
|
||
|
}
|
||
|
#endif
|
||
|
-
|
||