StackWalk64 on Windows - Get symbol name

故事扮演 提交于 2019-11-27 23:03:38

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;

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

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.

Cheeso

Check out the Stackwalker project on codeplex - it's open source. Works nicely.

I used your code and it also didn't work at first, until I noticed in the documentation that you first need to call SymInitialize, like SymInitialize(process, NULL, TRUE) . You can call this before RtlCaptureContext.

There are two problems to address first:

1) Name needs to be preallocated as pointed out by AShelly. You don't need malloc to do it:

#define MY_MAX_SYM_LEN 255
printStack()
{
    struct sym_pack_tag {
        IMAGEHLP_SYMBOL64  sym;
        char               name[MY_MAX_SYM_LEN];
    } sym_pack;
    IMAGEHLP_SYMBOL64     *symbol = &sym_pack.sym;
    ...
    symbol->SizeOfStruct  = sizeof(IMAGEHLP_SYMBOL64 );
    symbol->MaxNameLength = MY_MAX_SYM_LEN;
    if (!SymGetSymFromAddr64( process, stack.AddrPC.Offset, &displacement, symbol )) ...

2) Its not ok to use RtlCaptureContext() to get context in 32-bit builds. If you have 64-bit machine then change IMAGE_FILE_MACHINE_I386 to the appropriate 64-bit type. If you have 32-bit build then use inline assembly to correctly set EBP, ESP and EIP. Here is one way to do it:

__declspec(naked) void WINAPI CaptureContext_X86ControlOnly(CONTEXT *context) {
  __asm {
    push ebp
    mov  ebp, esp
    mov  ecx, context            //ecx = [ebp + 8]
    pop  ebp                     //restore old frame
    pop  eax                     //pop return address
    pop  ecx                     //pop context as WINAPI needs. Note: ecx will stay the same
    mov [ecx]CONTEXT.ContextFlags, CONTEXT_CONTROL
    mov [ecx]CONTEXT.Ebp, ebp
    mov [ecx]CONTEXT.Eip, eax
    mov [ecx]CONTEXT.Esp, esp
    jmp  eax
  }
} //I'm writing from my memory - so step through the code above to double check.

Minor point - SymGetSymFromAddr64 is ok, but it is recommended to use SymFromAddr instead.

Good luck to all those tracing stack on Windows.

Tim Cooper

See this answer to what is essentially the same question:

https://stackoverflow.com/a/28276227/10592

Note that you need to make sure your users have the .pdb file, and that their process can find it - see that answer for more details.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!