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