Windows上的StackWalk64 - 获取符号名称

Mac*_*ade 10 c windows stack backtrace

好的,关于SO的第二个问题在一天之内.看起来像Windows编程让我开心......:S

我正在尝试在Win32可执行文件上获取函数调用堆栈.

今天早上,我也问了一个问题:

Win32 - 从C代码回溯

现在,我很确定该StackWalk64功能是关键.我已经阅读了一些关于如何使用它的文章,以及MS文档.

它实际上在我的测试程序中显示帧,所以它有点工作......

问题是我无法从堆栈信息中检索符号名称.

我正在使用这个SymGetSymFromAddr64功能UnDecorateSymbolName.但我只得到垃圾人物.

这是我的代码.希望它不要乱,因为我不熟悉Windows编程:

void printStack( void )
{
    BOOL                result;
    HANDLE              process;
    HANDLE              thread;
    CONTEXT             context;
    STACKFRAME64        stack;
    ULONG               frame;
    IMAGEHLP_SYMBOL64   symbol;
    DWORD64             displacement;
    char name[ 256 ];

    RtlCaptureContext( &context );
    memset( &stack, 0, sizeof( STACKFRAME64 ) );

    process                = GetCurrentProcess();
    thread                 = GetCurrentThread();
    displacement           = 0;
    stack.AddrPC.Offset    = context.Eip;
    stack.AddrPC.Mode      = AddrModeFlat;
    stack.AddrStack.Offset = context.Esp;
    stack.AddrStack.Mode   = AddrModeFlat;
    stack.AddrFrame.Offset = context.Ebp;
    stack.AddrFrame.Mode   = AddrModeFlat;

    for( frame = 0; ; frame++ )
    {
        result = StackWalk64
        (
            IMAGE_FILE_MACHINE_I386,
            process,
            thread,
            &stack,
            &context,
            NULL,
            SymFunctionTableAccess64,
            SymGetModuleBase64,
            NULL
        );

        symbol.SizeOfStruct  = sizeof( IMAGEHLP_SYMBOL64 );
        symbol.MaxNameLength = 255;

        SymGetSymFromAddr64( process, ( ULONG64 )stack.AddrPC.Offset, &displacement, &symbol );
        UnDecorateSymbolName( symbol.Name, ( PSTR )name, 256, UNDNAME_COMPLETE );

        printf
        (
            "Frame %lu:\n"
            "    Symbol name:    %s\n"
            "    PC address:     0x%08LX\n"
            "    Stack address:  0x%08LX\n"
            "    Frame address:  0x%08LX\n"
            "\n",
            frame,
            symbol.Name,
            ( ULONG64 )stack.AddrPC.Offset,
            ( ULONG64 )stack.AddrStack.Offset,
            ( ULONG64 )stack.AddrFrame.Offset
        );

        if( !result )
        {
            break;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

实际输出是:

Frame 0:
    Symbol name:    ????????????
    PC address:     0x00BA2763
    Stack address:  0x00000000
    Frame address:  0x0031F7E8

Frame 1:
    Symbol name:    ?????????????
    PC address:     0x00BB4FFF
    Stack address:  0x00000000
    Frame address:  0x0031F940

Frame 2:
    Symbol name:    ?????????????
    PC address:     0x00BB4E2F
    Stack address:  0x00000000
    Frame address:  0x0031F990

Frame 3:
    Symbol name:    ?????????????
    PC address:     0x75BE3677
    Stack address:  0x00000000
    Frame address:  0x0031F998

Frame 4:
    Symbol name:    ?????????????
    PC address:     0x770F9D72
    Stack address:  0x00000000
    Frame address:  0x0031F9A4

Frame 5:
    Symbol name:    ?????????????
    PC address:     0x770F9D45
    Stack address:  0x00000000
    Frame address:  0x0031F9E4

Frame 6:
    Symbol name:    ?????????????
    PC address:     0x770F9D45
    Stack address:  0x00000000
    Frame address:  0x0031F9E4
Run Code Online (Sandbox Code Playgroud)

看起来很奇怪堆栈地址总是0 ...任何帮助赞赏:)

谢谢大家!

编辑

我正在寻找一个简单的C解决方案,没有第三方库......

ASh*_*lly 6

您已设置symbol.MaxNameLength为255,但您在堆栈上分配了"符号" IMAGEHLP_SYMBOL64 symbol;.该类型定义为:

typedef struct _IMAGEHLP_SYMBOL64 {
  DWORD   SizeOfStruct;
  DWORD64 Address;
  DWORD   Size;
  DWORD   Flags;
  DWORD   MaxNameLength;
  TCHAR   Name[1];
} IMAGEHLP_SYMBOL64;
Run Code Online (Sandbox Code Playgroud)

请注意,Name字段默认只有一个字符.如果要存储更大的名称,则需要执行以下操作:

 const int MaxNameLen = 255;
 IMAGEHLP_SYMBOL64* pSymbol = 
       malloc(sizeof(IMAGEHLP_SYMBOL64)+MaxNameLen*sizeof(TCHAR));
 pSymbol->MaxNameLength = MaxNameLen;
Run Code Online (Sandbox Code Playgroud)

否则,SymGetSymFromAddr64()很可能会覆盖内存.以下是该结构的帮助页面(强调添加):

MaxNameLength:Name成员可以包含的字符串的最大长度(以字符为单位),不包括以null结尾的字符.由于符号名称的长度可能不同,因此该数据结构 由调用者分配.使用此成员,以便库知道符号名称可以使用多少内存.


Che*_*eso 5

查看codeplex上Stackwalker项目 - 它是开源的.很好地工作.