1

我正在尝试为我的应用程序打印堆栈跟踪。我不能使用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

4

1 回答 1

1

您要做的是展开堆栈。而不是解决这个丑陋的烂摊子,我只会告诉你所涉及的一般原则。在 x86 和 x86_64 上,ebp/rsp 和 esp/rsp 寄存器形成内存位置的隐式链接列表。每个 esp/rsp 指向当前栈帧的顶部,每个 ebp/rbp 指向前一个栈帧的底部。有了这些知识,遍历框架就相当简单了。

于 2012-09-06T01:22:28.810 回答