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

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

问题描述

好吧,对SO在一天的第二个问题。看起来像Windows程序设计让我很开心......:•

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 code回溯

现在,我是pretty确保 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.

下面是我的code。希望这不是令人眼花缭乱的,因为我不习惯到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:\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;
        }
    }
}

实际的输出是:

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的方式...任何帮助AP preciated:)

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符号; 。该类型定义为:

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;

注意Name字段只有在默认情况下一个字符。如果要存储更大的名称,你需要做的是这样的:

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 :最大长度
  字符串的名称成员都可以
  包含在字符,不包括
  空终止符。
  因为符号名称可以在变化
  长度,该数据结构是
   调用方分配 的。该成员
  使用这样的文库知道多少
  内存可用于通过使用
  符号的名称。

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.

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

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