🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Untitled

posted in DruinkJournal
Published February 22, 2007
Advertisement
Stack walking is cool :D

My memory manager can now tell me what line an allocation was on, by walking up the stack 4 frames (Because my stack walking function is 4 functions deep - operator new -> PMemory::Allocate() -> PMemory::InternalAlloc() -> PMemory::DetermineCaller()).

Here's some code for anyone who cares:
#include #pragma comment(lib,"dbghelp.lib")static const int s_nFramesToWalk = 4;void PMemory::DetermineCaller(Allocation* pAllocation){	DWORD dwMachineType;	CONTEXT theContext;	memset(&theContext, 0, sizeof(theContext));	RtlCaptureContext(&theContext);	STACKFRAME64 theStackFrame;	memset(&theStackFrame, 0, sizeof(theStackFrame));#ifdef _M_IX86	dwMachineType = IMAGE_FILE_MACHINE_I386;	theStackFrame.AddrPC.Offset = theContext.Eip;	theStackFrame.AddrPC.Mode = AddrModeFlat;	theStackFrame.AddrFrame.Offset = theContext.Ebp;	theStackFrame.AddrFrame.Mode = AddrModeFlat;	theStackFrame.AddrStack.Offset = theContext.Esp;	theStackFrame.AddrStack.Mode = AddrModeFlat;#elif _M_X64	dwMachineType = IMAGE_FILE_MACHINE_AMD64;	theStackFrame.AddrPC.Offset = theContext.Rip;	theStackFrame.AddrPC.Mode = AddrModeFlat;	theStackFrame.AddrFrame.Offset = theContext.Rsp;	theStackFrame.AddrFrame.Mode = AddrModeFlat;	theStackFrame.AddrStack.Offset = theContext.Rsp;	theStackFrame.AddrStack.Mode = AddrModeFlat;#elif _M_IA64	dwMachineType = IMAGE_FILE_MACHINE_IA64;	theStackFrame.AddrPC.Offset = theContext.StIIP;	theStackFrame.AddrPC.Mode = AddrModeFlat;	theStackFrame.AddrFrame.Offset = theContext.IntSp;	theStackFrame.AddrFrame.Mode = AddrModeFlat;	theStackFrame.AddrBStore.Offset = theContext.RsBSP;	theStackFrame.AddrBStore.Mode = AddrModeFlat;	theStackFrame.AddrStack.Offset = theContext.IntSp;	theStackFrame.AddrStack.Mode = AddrModeFlat;#else#	error "Platform not supported!"#endif	// Walk up the stack to the caller	for(int i=0; i	{		if(!StackWalk64(dwMachineType, GetCurrentProcess(), GetCurrentThread(), &theStackFrame,			NULL, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))		{			strcpy(pAllocation->szFile, "??");			pAllocation->nLine = 0;			strcpy(pAllocation->szFunc, "??");			return;		}	}	// Get file/line number	{		IMAGEHLP_LINE64 theLine;		DWORD dwDisplacement;		memset(&theLine, 0, sizeof(theLine));		theLine.SizeOfStruct = sizeof(theLine);		if(!SymGetLineFromAddr64(GetCurrentProcess(), theStackFrame.AddrPC.Offset, &dwDisplacement, &theLine))		{			strcpy(pAllocation->szFile, "??");			pAllocation->nLine = 0;		}		else		{			const char* pszFile = strrchr(theLine.FileName, '\\');			if(!pszFile) pszFile = theLine.FileName;			else ++pszFile;			strncpy(pAllocation->szFile, pszFile, Allocation::cnBufferSize);			pAllocation->nLine = theLine.LineNumber;		}	}	// Get function name	{		unsigned char byBuffer[sizeof(IMAGEHLP_SYMBOL64) + Allocation::cnBufferSize];		IMAGEHLP_SYMBOL64* pSymbol = (IMAGEHLP_SYMBOL64*)byBuffer;		DWORD64 dwDisplacement;		memset(pSymbol, 0, sizeof(IMAGEHLP_SYMBOL64) + Allocation::cnBufferSize);		pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);		pSymbol->MaxNameLength = Allocation::cnBufferSize;		if(!SymGetSymFromAddr64(GetCurrentProcess(), theStackFrame.AddrPC.Offset, &dwDisplacement, pSymbol))			strcpy(pAllocation->szFunc, "??");		else			strcpy(pAllocation->szFunc, pSymbol->Name);	}}

The only down side of this code is that it only works in debug builds (obviously, I won't be using my memory tracker in a real app), and it only works on XP+, thanks to the call to RtlCaptureContext.

Still - Yay, it works nicely [smile]
Previous Entry Untitled
Next Entry Untitled
0 likes 3 comments

Comments

MindWipe
Stack wanking?
February 23, 2007 04:01 AM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement
Advertisement