Windows 上的 StackWalk64 - 获取符号名称 [英] StackWalk64 on Windows - Get symbol name
问题描述
好的,一天后关于 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:
现在,我很确定 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屋!