void PrepareStacktrace() {
	InitImageHlpDll();

	// Record list of loaded DLLs.
	PRINT("DLL information:");
	SymEnumerateModules(GetCurrentProcess(), EnumModules, NULL);
}
Beispiel #2
0
/** 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);
}