• Advertisement
Sign in to follow this  
  • entries
    557
  • comments
    1237
  • views
    422689

Untitled

Sign in to follow this  

63 views

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]
Sign in to follow this  


3 Comments


Recommended Comments

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement