适用于x64 Windows的Stack Walker

时间:2012-09-06 01:19:48

标签: windows 64-bit stack-trace

我正在尝试为我的应用程序打印堆栈跟踪。我无法使用StackWalk64,因为我的应用程序随optimization disabled一起发布。对于x86,我们使用了strace某人在codeprex上写的人但是我找不到与x64类似的内容。以下是我在网上为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;
}

要使其在x64

上运行,需要进行哪些更改

1 个答案:

答案 0 :(得分:1)

您要做的是展开堆栈。我会告诉你所涉及的一般原则,而不是修复那些丑陋的混乱。在x86和x86_64上,ebp / rsp和esp / rsp寄存器形成内存位置的隐式链接列表。每个esp / rsp指向当前堆栈帧的顶部,每个ebp / rbp指向前一个堆栈帧的底部。有了这些知识,走遍框架是相当微不足道的。