void PrepareStacktrace() { InitImageHlpDll(); // Record list of loaded DLLs. PRINT("DLL information:"); SymEnumerateModules(GetCurrentProcess(), EnumModules, NULL); }
/** Print out a stacktrace. */ static void Stacktrace(LPEXCEPTION_POINTERS e, HANDLE hThread = INVALID_HANDLE_VALUE) { PIMAGEHLP_SYMBOL pSym; STACKFRAME sf; HANDLE process, thread; DWORD dwModBase, Disp, dwModAddrToPrint; BOOL more = FALSE; int count = 0; char modname[MAX_PATH]; process = GetCurrentProcess(); if (!InitImageHlpDll()) return; // List all loaded DLLs. PRINT("DLL information:"); SymEnumerateModules(process, EnumModules, NULL); bool suspended = false; CONTEXT c; if (e) { c = *e->ContextRecord; thread = GetCurrentThread(); } else { SuspendThread(hThread); suspended = true; memset(&c, 0, sizeof(CONTEXT)); c.ContextFlags = CONTEXT_FULL; // FIXME: This does not work if you want to dump the current thread's stack if (!GetThreadContext(hThread, &c)) { SymCleanup(process); // Unintialize IMAGEHLP.DLL ResumeThread(hThread); return; } thread = hThread; } ZeroMemory(&sf, sizeof(sf)); sf.AddrPC.Offset = c.Eip; sf.AddrStack.Offset = c.Esp; sf.AddrFrame.Offset = c.Ebp; sf.AddrPC.Mode = AddrModeFlat; sf.AddrStack.Mode = AddrModeFlat; sf.AddrFrame.Mode = AddrModeFlat; // use globalalloc to reduce risk for allocator related deadlock pSym = (PIMAGEHLP_SYMBOL)GlobalAlloc(GMEM_FIXED, 16384); char* printstrings = (char*)GlobalAlloc(GMEM_FIXED, 0); PRINT("Stacktrace:"); bool containsOglDll = false; while (true) { more = StackWalk( IMAGE_FILE_MACHINE_I386, // TODO: fix this for 64 bit windows? process, thread, &sf, &c, NULL, SymFunctionTableAccess, SymGetModuleBase, NULL ); if (!more || sf.AddrFrame.Offset == 0 || count > MAX_STACK_DEPTH) { break; } dwModBase = SymGetModuleBase(process, sf.AddrPC.Offset); if (dwModBase) { GetModuleFileName((HINSTANCE)dwModBase, modname, MAX_PATH); } else { strcpy(modname, "Unknown"); } pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL); pSym->MaxNameLength = MAX_PATH; char* printstringsnew = (char*) GlobalAlloc(GMEM_FIXED, (count + 1) * BUFFER_SIZE); memcpy(printstringsnew, printstrings, count * BUFFER_SIZE); GlobalFree(printstrings); printstrings = printstringsnew; if (SymGetSymFromAddr(process, sf.AddrPC.Offset, &Disp, pSym)) { // This is the code path taken on VC if debugging syms are found. SNPRINTF(printstrings + count * BUFFER_SIZE, BUFFER_SIZE, "(%d) %s(%s+%#0lx) [0x%08lX]", count, modname, pSym->Name, Disp, sf.AddrPC.Offset); } else { // This is the code path taken on MinGW, and VC if no debugging syms are found. if (strstr(modname, ".exe")) { // for the .exe, we need the absolute address dwModAddrToPrint = sf.AddrPC.Offset; } else { // for DLLs, we need the module-internal/relative address dwModAddrToPrint = sf.AddrPC.Offset - dwModBase; } SNPRINTF(printstrings + count * BUFFER_SIZE, BUFFER_SIZE, "(%d) %s [0x%08lX]", count, modname, dwModAddrToPrint); } // OpenGL lib names (ATI): "atioglxx.dll" "atioglx2.dll" containsOglDll = containsOglDll || strstr(modname, "atiogl"); // OpenGL lib names (Nvidia): "nvoglnt.dll" "nvoglv32.dll" "nvoglv64.dll" (last one is a guess) containsOglDll = containsOglDll || strstr(modname, "nvogl"); // OpenGL lib names (Intel): "ig4dev32.dll" "ig4dev64.dll" containsOglDll = containsOglDll || strstr(modname, "ig4dev"); ++count; } // Unintialize IMAGEHLP.DLL SymCleanup(process); if (suspended) { ResumeThread(hThread); } if (containsOglDll) { PRINT("This stack trace indicates a problem with your graphic card driver. " "Please try upgrading or downgrading it. " "Specifically recommended is the latest driver, and one that is as old as your graphic card. " "Make sure to use a driver removal utility, before installing other drivers."); } for (int i = 0; i < count; ++i) { PRINT("%s", printstrings + i * BUFFER_SIZE); } GlobalFree(printstrings); GlobalFree(pSym); }