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]