Windows 上的 StackWalk64 - 获取符号名称 [英] StackWalk64 on Windows - Get symbol name

查看:50
本文介绍了Windows 上的 StackWalk64 - 获取符号名称的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,一天后关于 SO 的第二个问题.看起来 Windows 编程让我很开心……:S

Alright, second question on SO in one day. Looks like Windows programming makes me happy... : S

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

I'm currently trying to get the function call stack on a Win32 executable.

今天早上,我还问了一个关于这个的问题:

This morning, I've also asked a question about this:

Win32 - 来自 C 代码的回溯

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

Now, I'm pretty sure that the StackWalk64 function is the key for this. I've read some articles on how to use it, as well as the MS documentation.

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

It actually displays frames on my test program, so it kinda work...

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

The problem is that I'm not able to retrieve the symbol name from the stack informations.

为此,我使用 SymGetSymFromAddr64 函数和 UnDecorateSymbolName.但我只会得到垃圾字符.

I'm using the SymGetSymFromAddr64 function for this, with UnDecorateSymbolName. But I only get junk characters.

这是我的代码.希望不要乱七八糟,因为我不习惯 Windows 编程:

Here's my code. Hope its not to messy, as I'm not used to Windows programming:

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:
"
            "    Symbol name:    %s
"
            "    PC address:     0x%08LX
"
            "    Stack address:  0x%08LX
"
            "    Frame address:  0x%08LX
"
            "
",
            frame,
            symbol.Name,
            ( ULONG64 )stack.AddrPC.Offset,
            ( ULONG64 )stack.AddrStack.Offset,
            ( ULONG64 )stack.AddrFrame.Offset
        );

        if( !result )
        {
            break;
        }
    }
}

实际输出为:

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

顺便说一句,堆栈地址总是 0 似乎很奇怪......任何帮助表示赞赏:)

Seems weird that the stack address is always 0 by the way... Any help appreciated : )

谢谢大家!

编辑

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

I'm looking for a plain C solution, without third party libraries...

推荐答案

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

You have set symbol.MaxNameLength to 255, but you allocated "symbol" on the stack with IMAGEHLP_SYMBOL64 symbol;. That type is defined as:

typedef struct _IMAGEHLP_SYMBOL64 {
  DWORD   SizeOfStruct;
  DWORD64 Address;
  DWORD   Size;
  DWORD   Flags;
  DWORD   MaxNameLength;
  TCHAR   Name[1];
} IMAGEHLP_SYMBOL64;

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

Notice that the Name field only has one character by default. If you want to store bigger names, you need to do something like:

 const int MaxNameLen = 255;
 IMAGEHLP_SYMBOL64* pSymbol = 
       malloc(sizeof(IMAGEHLP_SYMBOL64)+MaxNameLen*sizeof(TCHAR));
 pSymbol->MaxNameLength = MaxNameLen;

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

Otherwise, SymGetSymFromAddr64() is likely to overwrite memory. Here is what the help page for the structure says (emphasis added):

MaxNameLength:最大长度Name 成员可以的字符串包含,在字符中,不包括空终止字符.因为符号名称可能会有所不同长度,这个数据结构是由调用者分配.该会员被使用,所以图书馆知道有多少内存可供使用符号名称.

MaxNameLength: The maximum length of the string that the Name member can contain, in characters, not including the null-terminating character. Because symbol names can vary in length, this data structure is allocated by the caller. This member is used so the library knows how much memory is available for use by the symbol name.

这篇关于Windows 上的 StackWalk64 - 获取符号名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆