I am trying to print the stack trace for my application. I cannot use StackWalk64 as my application is release with optimization disabled. For x86 we were using strace library somebody written on codeprex But I did not find anything similar for x64. Following is the code I found on web for x86.
#include <Windows.h>
#include <DbgHelp.h>
#include <stdio.h>
#define INVALID_FP_RET_ADDR_VALUE 0x00000000
BOOL g_fSymInit;
HANDLE g_hProcess;
BOOL DisplaySymbolDetails(DWORD dwAddress)
{
DWORD64 displacement = 0;
ULONG64 buffer[(sizeof(SYMBOL_INFO) +
MAX_SYM_NAME*sizeof(TCHAR) +
sizeof(ULONG64) - 1) /
sizeof(ULONG64)];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYM_NAME;
if (SymFromAddr(g_hProcess,dwAddress,&displacement,pSymbol))
{
// Try to get the Module details
IMAGEHLP_MODULE64 moduleinfo;
moduleinfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
if (SymGetModuleInfo64(g_hProcess,pSymbol->Address,&moduleinfo))
{
printf("%s!",moduleinfo.ModuleName);
}
else
{
printf("<ErrorModuleInfo_%d>!", GetLastError());
}
// now print the function name
if (pSymbol->MaxNameLen > 0)
{
printf("%s",pSymbol->Name);
}
else
{
printf("<Unknown_Function>");
}
}
else
{
printf(" <Unable to get symbol details_%d>", GetLastError());
}
return TRUE;
}
bool WalkTheStack()
{
DWORD _ebp = INVALID_FP_RET_ADDR_VALUE;
DWORD dwIPOfCurrentFunction = (DWORD)&WalkTheStack;
// Get the current Frame pointer
__asm
{
mov [_ebp], ebp
}
// We cannot walk the stack (yet!) without a frame pointer
if (_ebp == INVALID_FP_RET_ADDR_VALUE)
return false;
printf("CurFP\t\t\tRetAddr\n");
DWORD *pCurFP = (DWORD *)_ebp;
BOOL fFirstFP = TRUE;
while (pCurFP != INVALID_FP_RET_ADDR_VALUE)
{
// pointer arithmetic works in terms of type pointed to. Thus,
// "+1" below is equivalent of 4 bytes since we are doing DWORD
// math.
DWORD pRetAddrInCaller = (*((DWORD *)(pCurFP + 1)));
printf("%p\t\t%p ",pCurFP, (DWORD *)pRetAddrInCaller);
if (g_fSymInit)
{
if (fFirstFP)
{
fFirstFP = FALSE;
}
DisplaySymbolDetails(dwIPOfCurrentFunction);
// To get the name of the next function up the stack,
// we use the return address of the current frame
dwIPOfCurrentFunction = pRetAddrInCaller;
}
printf("\n");
if (pRetAddrInCaller == INVALID_FP_RET_ADDR_VALUE)
{
// StackWalk is over now...
break;
}
// move up the stack to our caller
DWORD pCallerFP = *((DWORD *)pCurFP);
pCurFP = (DWORD *)pCallerFP;
}
return true;
}
int main ( int argc, char **argv) {
g_fSymInit = FALSE;
g_hProcess = GetCurrentProcess();
if (!SymInitialize(g_hProcess, NULL,TRUE)) {
printf("Unable to initialize symbols!\n\n");
} else {
g_fSymInit = TRUE;
}
SymSetOptions(SYMOPT_UNDNAME|SYMOPT_INCLUDE_32BIT_MODULES|SYMOPT_ALLOW_ABSOLUTE_SYMBOLS);
WalkTheStack();
return 0;
}
What changes would be required to make it work on x64
What you want to do is unroll the stack. Rather than fix that ugly mess I’ll just tell you the general principles involved. On x86 and x86_64 the ebp/rsp and esp/rsp registers form an implicit linked list of memory locations. Each esp/rsp points to the top of the current stack frame, and each ebp/rbp points to the bottom of the previous stack frame. Armed with this knowledge, it’s fairly trivial to walk through the frames.