Backtrace Dumps
Robert Shearman
rob at codeweavers.com
Mon Aug 16 16:32:14 CDT 2004
Hi,
I propose the addition of this new debug tool that will allow developers
to output backtraces to the console, without having to interact with a
debugger. It can give a useful indication of how functions are being
called in situations where a break point is not appropriate.
To use it, simply include "wine/backtrace.h" somewhere and then call
dump_backtrace(), which will generate an output similar to the following:
Backtrace:
0xffffe40e
NTDLL_wait_for_multiple_objects+0x103
NtWaitForMultipleObjects+0x50
WaitForMultipleObjectsEx+0xa3
WaitForSingleObject+0x36
dump_backtrace+0x4c
InternetConnectW+0xf9
InternetConnectA+0x115
winapi_test+0x12f
func_http+0x1a
run_test+0x62
__wine_exe_main+0x163
start_process+0xc3
wine_switch_to_stack+0x11
Rob
Changelog:
Add code to generate backtrace dumps.
-------------- next part --------------
--- /dev/null 2003-09-15 14:40:47.000000000 +0100
+++ wine/include/wine/backtrace.h 2004-08-16 21:08:47.454518512 +0100
@@ -0,0 +1,151 @@
+/*
+ * Backtrace Generator
+ *
+ * Copyright 2004 Eric Poech
+ * Copyright 2004 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <winver.h>
+#include <dbghelp.h>
+
+#define MAKE_FUNCPTR(f) static typeof(f) * p##f
+
+MAKE_FUNCPTR(StackWalk);
+MAKE_FUNCPTR(SymGetModuleBase);
+MAKE_FUNCPTR(SymFunctionTableAccess);
+MAKE_FUNCPTR(SymInitialize);
+MAKE_FUNCPTR(SymGetSymFromAddr);
+MAKE_FUNCPTR(SymGetModuleInfo);
+
+static BOOL init_backtrace()
+{
+ HMODULE hmodDbgHelp = LoadLibraryA("dbghelp");
+
+ #define GETFUNC(x) \
+ p##x = (typeof(x)*)GetProcAddress(hmodDbgHelp, #x); \
+ if (!p##x) \
+ { \
+ return FALSE; \
+ }
+
+ GETFUNC(StackWalk);
+ GETFUNC(SymGetModuleBase);
+ GETFUNC(SymFunctionTableAccess);
+ GETFUNC(SymInitialize);
+ GETFUNC(SymGetSymFromAddr);
+ GETFUNC(SymGetModuleInfo);
+
+ pSymInitialize(GetCurrentProcess(), NULL, TRUE);
+
+ return TRUE;
+}
+
+static void dump_backtrace_for_thread(HANDLE hThread)
+{
+ STACKFRAME sf;
+ CONTEXT context;
+ DWORD dwImageType;
+
+ if (!pStackWalk)
+ if (!init_backtrace())
+ return;
+
+ /* can't use this function for current thread as GetThreadContext
+ * doesn't support getting context from current thread */
+ if (hThread == GetCurrentThread())
+ return;
+
+ DPRINTF("Backtrace:\n");
+
+ memset(&context, 0, sizeof(context));
+ context.ContextFlags = CONTEXT_FULL;
+
+ SuspendThread(hThread);
+
+ if (!GetThreadContext(hThread, &context))
+ {
+ DPRINTF("Couldn't get thread context (error %ld)\n", GetLastError());
+ ResumeThread(hThread);
+ return;
+ }
+
+ memset(&sf, 0, sizeof(sf));
+
+#ifdef __i386__
+ sf.AddrFrame.Offset = context.Ebp;
+ sf.AddrFrame.Mode = AddrModeFlat;
+ sf.AddrPC.Offset = context.Eip;
+ sf.AddrPC.Mode = AddrModeFlat;
+ dwImageType = IMAGE_FILE_MACHINE_I386;
+#else
+# error You need to fill in the STACKFRAME structure for your architecture
+#endif
+
+ while (pStackWalk(dwImageType, GetCurrentProcess(),
+ hThread, &sf, &context, NULL, pSymFunctionTableAccess,
+ pSymGetModuleBase, NULL))
+ {
+ BYTE buffer[256];
+ IMAGEHLP_SYMBOL * pSymbol = (IMAGEHLP_SYMBOL *)buffer;
+ DWORD dwDisplacement;
+
+ pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
+ pSymbol->MaxNameLength = sizeof(buffer) - sizeof(IMAGEHLP_SYMBOL) + 1;
+
+ if (!pSymGetSymFromAddr(GetCurrentProcess(), sf.AddrPC.Offset,
+ &dwDisplacement, pSymbol))
+ {
+ IMAGEHLP_MODULE ModuleInfo;
+ ModuleInfo.SizeOfStruct = sizeof(ModuleInfo);
+
+ if (!pSymGetModuleInfo(GetCurrentProcess(), sf.AddrPC.Offset,
+ &ModuleInfo))
+ DPRINTF("\t%p\n", (void*)sf.AddrPC.Offset);
+ else
+ DPRINTF("\t%s+0x%lx\n", ModuleInfo.ImageName,
+ sf.AddrPC.Offset - ModuleInfo.BaseOfImage);
+ }
+ else if (dwDisplacement)
+ DPRINTF("\t%s+0x%lx\n", pSymbol->Name, dwDisplacement);
+ else
+ DPRINTF("\t%s\n", pSymbol->Name);
+ }
+
+ ResumeThread(hThread);
+}
+
+static DWORD WINAPI dump_thread_proc(LPVOID lpParameter)
+{
+ dump_backtrace_for_thread((HANDLE)lpParameter);
+ return 0;
+}
+
+/* cannot get valid context from current thread, so we have to execute
+ * bactrace from another thread */
+static void dump_backtrace()
+{
+ HANDLE hCurrentThread;
+ HANDLE hThread;
+ DWORD dwThreadId;
+ DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
+ GetCurrentProcess(), &hCurrentThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
+ hThread = CreateThread(NULL, 0, dump_thread_proc, (LPVOID)hCurrentThread,
+ 0, &dwThreadId);
+ WaitForSingleObject(hThread, INFINITE);
+ CloseHandle(hThread);
+ CloseHandle(hCurrentThread);
+}
More information about the wine-patches
mailing list