C++ 如何使用 Windows x64 记录堆栈帧

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/590160/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 16:07:50  来源:igfitidea点击:

How to Log Stack Frames with Windows x64

c++cwinapi64-bitcallstack

提问by RED SOFT ADAIR

I am using Stackdumps with Win32, to write all return adresses into my logfile. I match these with a mapfile later on (see my article [Post Mortem Debugging][1]).

我在 Win32 中使用 Stackdumps,将所有返回地址写入我的日志文件。稍后我将这些与映射文件匹配(请参阅我的文章 [Post Mortem Debugging][1])。

EDIT:: Problem solved - see my own answer below.

编辑:: 问题已解决 - 请参阅下面我自己的答案。

With Windows x64 i do not find a reliable way to write only the return adresses into the logfile. I tried several ways:

对于 Windows x64,我没有找到仅将返回地址写入日志文件的可靠方法。我尝试了几种方法:

Trial 1: Pointer Arithmetic:

试验 1:指针运算:

   CONTEXT Context;
   RtlCaptureContext(&Context);
   char *eNextBP  = (char *)Context.Rdi;
   for(ULONG Frame = 0; eNextBP ; Frame++)
   {        
       char *pBP = eNextBP;
       eNextBP = *(char **)pBP; // Next BP in Stack
       fprintf(LogFile, "*** %2d called from %016LX  (pBP at %016LX)\n", Frame, 
              (ULONG64)*(char **)(pBP + 8), (ULONG64)pBP);

    }

This works fine in the debug version - but it crashes in the release version. The value of Context.Rdi has no usable value there. I did check for differences in the compiler settings (visual Studio 2005). I have not found anything suspicious.

这在调试版本中工作正常 - 但在发布版本中崩溃。Context.Rdi 的值在那里没有可用的值。我确实检查了编译器设置(visual Studio 2005)中的差异。我没有发现任何可疑之处。

Trial 2: Using StackWalk64

试验 2:使用 StackWalk64

RtlCaptureContext(&Context);
STACKFRAME64 stk;
memset(&stk, 0, sizeof(stk));

stk.AddrPC.Offset       = Context.Rip;
stk.AddrPC.Mode         = AddrModeFlat;
stk.AddrStack.Offset    = Context.Rsp;
stk.AddrStack.Mode      = AddrModeFlat;
stk.AddrFrame.Offset    = Context.Rbp;
stk.AddrFrame.Mode      = AddrModeFlat;


for(ULONG Frame = 0; ; Frame++)
{
    BOOL result = StackWalk64(
                            IMAGE_FILE_MACHINE_AMD64,   // __in      DWORD MachineType,
                            GetCurrentProcess(),        // __in      HANDLE hProcess,
                            GetCurrentThread(),         // __in      HANDLE hThread,
                            &stk,                       // __inout   LP STACKFRAME64 StackFrame,
                            &Context,                  // __inout   PVOID ContextRecord,
                             NULL,                     // __in_opt  PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
                             SymFunctionTableAccess64,                      // __in_opt  PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
                             SymGetModuleBase64,                     // __in_opt  PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
                             NULL                       // __in_opt  PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
                             );

    fprintf(gApplSetup.TraceFile, "*** %2d called from %016LX   STACK %016LX    FRAME %016LX\n", Frame, (ULONG64)stk.AddrPC.Offset, (ULONG64)stk.AddrStack.Offset, (ULONG64)stk.AddrFrame.Offset);
    if(! result)
        break;
}

This does not only dump the return addresses, but the WHOLE STACK. I receive about 1000 lines in my log file using this approach. I can use this, but i have to search trough the lines and some data of the stacks happens to be a valid code address.

这不仅会转储返回地址,还会转储整个堆栈。我使用这种方法在我的日志文件中收到大约 1000 行。我可以使用它,但我必须通过行进行搜索,并且堆栈的某些数据恰好是有效的代码地址。

Trial 3: Using Backtrace

试验 3:使用回溯

static USHORT (WINAPI
*s_pfnCaptureStackBackTrace)(ULONG, ULONG, PVOID*, PULONG) = 0;  
    if (s_pfnCaptureStackBackTrace == 0)  
    {  
        const HMODULE hNtDll = ::GetModuleHandle("ntdll.dll");  
        reinterpret_cast<void*&>(s_pfnCaptureStackBackTrace)
=  ::GetProcAddress(hNtDll, "RtlCaptureStackBackTrace");  
    }  
    PVOID myFrames[128];
    s_pfnCaptureStackBackTrace(0, 128, myFrames, NULL);

    for(int ndx = 0; ndx < 128; ndx++)
        fprintf(gApplSetup.TraceFile, "*** BackTrace %3d %016LX\n", ndx,  (ULONG64)myFrames[ndx]);

Results in no usable information.

结果没有可用的信息。

Has anyone implemented such a stack walk in x64 that does only write out the return adresses in the stack? Ive seen the approaches [StackTrace64][2], [StackWalker][3] and other ones. They either do not compile or they are much too much comlicated. It basically is a simple task!

有没有人在 x64 中实现过这样的堆栈遍历,只写出堆栈中的返回地址?我见过 [StackTrace64][2]、[StackWalker][3] 和其他方法。它们要么不编译,要么过于复杂。这基本上是一个简单的任务!

Sample StackDump64.cpp

示例 StackDump64.cpp

#include <Windows.h>
#include <DbgHelp.h>
#include <Winbase.h>

#include <stdio.h>

void WriteStackDump()

{

    FILE *myFile = fopen("StackDump64.log", "w+t");

    CONTEXT                       Context;
    memset(&Context, 0, sizeof(Context));
    RtlCaptureContext(&Context);

    RtlCaptureContext(&Context);
    STACKFRAME64 stk;
    memset(&stk, 0, sizeof(stk));

    stk.AddrPC.Offset       = Context.Rip;
    stk.AddrPC.Mode         = AddrModeFlat;
    stk.AddrStack.Offset    = Context.Rsp;
    stk.AddrStack.Mode      = AddrModeFlat;
    stk.AddrFrame.Offset    = Context.Rbp;
    stk.AddrFrame.Mode      = AddrModeFlat;


    for(ULONG Frame = 0; ; Frame++)
    {
        BOOL result = StackWalk64(
                                IMAGE_FILE_MACHINE_AMD64,   // __in      DWORD MachineType,
                                GetCurrentProcess(),        // __in      HANDLE hProcess,
                                GetCurrentThread(),         // __in      HANDLE hThread,
                                &stk,                       // __inout   LP STACKFRAME64 StackFrame,
                                &Context,                  // __inout   PVOID ContextRecord,
                                 NULL,                     // __in_opt  PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
                                 SymFunctionTableAccess64,                      // __in_opt  PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
                                 SymGetModuleBase64,                     // __in_opt  PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
                                 NULL                       // __in_opt  PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
                                 );

        fprintf(myFile, "*** %2d called from %016I64LX   STACK %016I64LX    AddrReturn %016I64LX\n", Frame, stk.AddrPC.Offset, stk.AddrStack.Offset, stk.AddrReturn.Offset);
        if(! result)
            break;
    }

    fclose(myFile);
}


void funcC()
{
    WriteStackDump();
}


void funcB()
{
    funcC();
}


void funcA()

{
    funcB();
}


int main(int argc, char *argv[])

{

    funcA();
}

Running this sample results in the follwing log file content:

运行此示例会产生以下日志文​​件内容:

***  0 called from 000000014000109E   STACK 000000000012F780    AddrReturn 0000000140005798
***  1 called from 000000001033D160   STACK 000000000012F788    AddrReturn 00000001400057B0
***  2 called from 00000001400057B0   STACK 000000000012F790    AddrReturn 0000000000000001
***  3 called from 0000000000000002   STACK 000000000012F798    AddrReturn 00000001400057B0
***  4 called from 0000000000000002   STACK 000000000012F7A0    AddrReturn 000000000012F7F0
***  5 called from 000000000012F7F0   STACK 000000000012F7A8    AddrReturn 0000000000000000
***  6 called from 0000000000000000   STACK 000000000012F7B0    AddrReturn 000007FF7250CF40
***  7 called from 000007FF7250CF40   STACK 000000000012F7B8    AddrReturn 000007FF7250D390
***  8 called from 000007FF7250D390   STACK 000000000012F7C0    AddrReturn 000007FF725B6950
***  9 called from 000007FF725B6950   STACK 000000000012F7C8    AddrReturn CCCCCCCCCCCCCCCC
*** 10 called from CCCCCCCCCCCCCCCC   STACK 000000000012F7D0    AddrReturn 000000001033D160
*** 11 called from 000000001033D160   STACK 000000000012F7D8    AddrReturn CCCCCCCCCCCCCCCC
*** 12 called from CCCCCCCCCCCCCCCC   STACK 000000000012F7E0    AddrReturn CCCCCCCCCCCCCCCC
*** 13 called from CCCCCCCCCCCCCCCC   STACK 000000000012F7E8    AddrReturn CCCCCCCCCCCCCCCC
*** 14 called from CCCCCCCCCCCCCCCC   STACK 000000000012F7F0    AddrReturn 0000000000000000
*** 15 called from 0000000000000000   STACK 000000000012F7F8    AddrReturn 0000000000000000
*** 16 called from 0000000000000000   STACK 000000000012F800    AddrReturn 0000000000000000
*** 17 called from 0000000000000000   STACK 000000000012F808    AddrReturn 0000000000000000
*** 18 called from 0000000000000000   STACK 000000000012F810    AddrReturn 0000000000000000
*** 19 called from 0000000000000000   STACK 000000000012F818    AddrReturn 0000000000000000
*** 20 called from 0000000000000000   STACK 000000000012F820    AddrReturn 00001F800010000F
*** 21 called from 00001F800010000F   STACK 000000000012F828    AddrReturn 0053002B002B0033
*** 22 called from 0053002B002B0033   STACK 000000000012F830    AddrReturn 00000206002B002B
*** 23 called from 00000206002B002B   STACK 000000000012F838    AddrReturn 0000000000000000
*** 24 called from 0000000000000000   STACK 000000000012F840    AddrReturn 0000000000000000
*** 25 called from 0000000000000000   STACK 000000000012F848    AddrReturn 0000000000000000
*** 26 called from 0000000000000000   STACK 000000000012F850    AddrReturn 0000000000000000
*** 27 called from 0000000000000000   STACK 000000000012F858    AddrReturn 0000000000000000
*** 28 called from 0000000000000000   STACK 000000000012F860    AddrReturn 0000000000000000
*** 29 called from 0000000000000000   STACK 000000000012F868    AddrReturn 0000000000000246
*** 30 called from 0000000000000246   STACK 000000000012F870    AddrReturn 000000000012F7F0
*** 31 called from 000000000012F7F0   STACK 000000000012F878    AddrReturn 0000000000000000
*** 32 called from 0000000000000000   STACK 000000000012F880    AddrReturn 0000000000000000
*** 33 called from 0000000000000000   STACK 000000000012F888    AddrReturn 000000000012F888
*** 34 called from 000000000012F888   STACK 000000000012F890    AddrReturn 0000000000000000
*** 35 called from 0000000000000000   STACK 000000000012F898    AddrReturn 0000000000000000
*** 36 called from 0000000000000000   STACK 000000000012F8A0    AddrReturn 000000000012FE10
*** 37 called from 000000000012FE10   STACK 000000000012F8A8    AddrReturn 0000000000000000
*** 38 called from 0000000000000000   STACK 000000000012F8B0    AddrReturn 0000000000000000
*** 39 called from 0000000000000000   STACK 000000000012F8B8    AddrReturn 0000000000000000
*** 40 called from 0000000000000000   STACK 000000000012F8C0    AddrReturn 0000000000000246
*** 41 called from 0000000000000246   STACK 000000000012F8C8    AddrReturn 0000000000000000
*** 42 called from 0000000000000000   STACK 000000000012F8D0    AddrReturn 0000000000000000
*** 43 called from 0000000000000000   STACK 000000000012F8D8    AddrReturn 0000000000000000
*** 44 called from 0000000000000000   STACK 000000000012F8E0    AddrReturn 0000000000000000
*** 45 called from 0000000000000000   STACK 000000000012F8E8    AddrReturn 0000000000000000
*** 46 called from 0000000000000000   STACK 000000000012F8F0    AddrReturn 000000000000027F
*** 47 called from 000000000000027F   STACK 000000000012F8F8    AddrReturn 0000000000000000
*** 48 called from 0000000000000000   STACK 000000000012F900    AddrReturn 0000000000000000
*** 49 called from 0000000000000000   STACK 000000000012F908    AddrReturn 0000FFFF00001F80
*** 50 called from 0000FFFF00001F80   STACK 000000000012F910    AddrReturn 0000000000000000
*** 51 called from 0000000000000000   STACK 000000000012F918    AddrReturn 0000000000000000
*** 52 called from 0000000000000000   STACK 000000000012F920    AddrReturn 0000000000000000
*** 53 called from 0000000000000000   STACK 000000000012F928    AddrReturn 0000000000000000
*** 54 called from 0000000000000000   STACK 000000000012F930    AddrReturn 0000000000000000
*** 55 called from 0000000000000000   STACK 000000000012F938    AddrReturn 0000000000000000
*** 56 called from 0000000000000000   STACK 000000000012F940    AddrReturn 0000000000000000
*** 57 called from 0000000000000000   STACK 000000000012F948    AddrReturn 0000000000000000
*** 58 called from 0000000000000000   STACK 000000000012F950    AddrReturn 0000000000000000
*** 59 called from 0000000000000000   STACK 000000000012F958    AddrReturn 0000000000000000
*** 60 called from 0000000000000000   STACK 000000000012F960    AddrReturn 0000000000000000
*** 61 called from 0000000000000000   STACK 000000000012F968    AddrReturn 0000000000000000
*** 62 called from 0000000000000000   STACK 000000000012F970    AddrReturn 0000000000000000
*** 63 called from 0000000000000000   STACK 000000000012F978    AddrReturn 0000000000000000
*** 64 called from 0000000000000000   STACK 000000000012F980    AddrReturn 0000000000000000
*** 65 called from 0000000000000000   STACK 000000000012F988    AddrReturn 0000000000000000
*** 66 called from 0000000000000000   STACK 000000000012F990    AddrReturn 0000000000000000
*** 67 called from 0000000000000000   STACK 000000000012F998    AddrReturn 0000000000000000
*** 68 called from 0000000000000000   STACK 000000000012F9A0    AddrReturn 0000000000000000
*** 69 called from 0000000000000000   STACK 000000000012F9A8    AddrReturn 0000000000000000
*** 70 called from 0000000000000000   STACK 000000000012F9B0    AddrReturn 0000000000000000
*** 71 called from 0000000000000000   STACK 000000000012F9B8    AddrReturn 0000000000000000
*** 72 called from 0000000000000000   STACK 000000000012F9C0    AddrReturn 0000000000000000
*** 73 called from 0000000000000000   STACK 000000000012F9C8    AddrReturn 0000000000000000
*** 74 called from 0000000000000000   STACK 000000000012F9D0    AddrReturn 0000000000000000
*** 75 called from 0000000000000000   STACK 000000000012F9D8    AddrReturn 0000000000000000
*** 76 called from 0000000000000000   STACK 000000000012F9E0    AddrReturn 0000000000000000
*** 77 called from 0000000000000000   STACK 000000000012F9E8    AddrReturn 0000000000000000
*** 78 called from 0000000000000000   STACK 000000000012F9F0    AddrReturn 0000000000000000
*** 79 called from 0000000000000000   STACK 000000000012F9F8    AddrReturn 0000000000000000
*** 80 called from 0000000000000000   STACK 000000000012FA00    AddrReturn 0000000000000000
*** 81 called from 0000000000000000   STACK 000000000012FA08    AddrReturn 0000000000000000
*** 82 called from 0000000000000000   STACK 000000000012FA10    AddrReturn 0000000000000000
*** 83 called from 0000000000000000   STACK 000000000012FA18    AddrReturn 0000000000000000
*** 84 called from 0000000000000000   STACK 000000000012FA20    AddrReturn 0000000000000000
*** 85 called from 0000000000000000   STACK 000000000012FA28    AddrReturn 0000000000000000
*** 86 called from 0000000000000000   STACK 000000000012FA30    AddrReturn 0000000000000000
*** 87 called from 0000000000000000   STACK 000000000012FA38    AddrReturn 0000000000000000
*** 88 called from 0000000000000000   STACK 000000000012FA40    AddrReturn 0000000000000000
*** 89 called from 0000000000000000   STACK 000000000012FA48    AddrReturn 0000000000000000
*** 90 called from 0000000000000000   STACK 000000000012FA50    AddrReturn 0000000000000000
*** 91 called from 0000000000000000   STACK 000000000012FA58    AddrReturn 0000000000000000
*** 92 called from 0000000000000000   STACK 000000000012FA60    AddrReturn 0000000000000000
*** 93 called from 0000000000000000   STACK 000000000012FA68    AddrReturn 0000000000000000
*** 94 called from 0000000000000000   STACK 000000000012FA70    AddrReturn 0000000000000000
*** 95 called from 0000000000000000   STACK 000000000012FA78    AddrReturn 0000000000000000
*** 96 called from 0000000000000000   STACK 000000000012FA80    AddrReturn 0000000000000000
*** 97 called from 0000000000000000   STACK 000000000012FA88    AddrReturn 0000000000000000
*** 98 called from 0000000000000000   STACK 000000000012FA90    AddrReturn 0000000000000000
*** 99 called from 0000000000000000   STACK 000000000012FA98    AddrReturn 0000000000000000
*** 100 called from 0000000000000000   STACK 000000000012FAA0    AddrReturn 0000000000000000
*** 101 called from 0000000000000000   STACK 000000000012FAA8    AddrReturn 0000000000000000
*** 102 called from 0000000000000000   STACK 000000000012FAB0    AddrReturn 0000000000000000
*** 103 called from 0000000000000000   STACK 000000000012FAB8    AddrReturn 0000000000000000
*** 104 called from 0000000000000000   STACK 000000000012FAC0    AddrReturn 0000000000000000
*** 105 called from 0000000000000000   STACK 000000000012FAC8    AddrReturn 0000000000000000
*** 106 called from 0000000000000000   STACK 000000000012FAD0    AddrReturn 0000000000000000
*** 107 called from 0000000000000000   STACK 000000000012FAD8    AddrReturn 0000000000000000
*** 108 called from 0000000000000000   STACK 000000000012FAE0    AddrReturn 0000000000000000
*** 109 called from 0000000000000000   STACK 000000000012FAE8    AddrReturn 0000000000000000
*** 110 called from 0000000000000000   STACK 000000000012FAF0    AddrReturn 0000000000000000
*** 111 called from 0000000000000000   STACK 000000000012FAF8    AddrReturn 0000000000000000
*** 112 called from 0000000000000000   STACK 000000000012FB00    AddrReturn 0000000000000000
*** 113 called from 0000000000000000   STACK 000000000012FB08    AddrReturn 0000000000000000
*** 114 called from 0000000000000000   STACK 000000000012FB10    AddrReturn 0000000000000000
*** 115 called from 0000000000000000   STACK 000000000012FB18    AddrReturn 0000000000000000
*** 116 called from 0000000000000000   STACK 000000000012FB20    AddrReturn 0000000000000000
*** 117 called from 0000000000000000   STACK 000000000012FB28    AddrReturn 0000000000000000
*** 118 called from 0000000000000000   STACK 000000000012FB30    AddrReturn 0000000000000000
*** 119 called from 0000000000000000   STACK 000000000012FB38    AddrReturn 0000000000000000
*** 120 called from 0000000000000000   STACK 000000000012FB40    AddrReturn 0000000000000000
*** 121 called from 0000000000000000   STACK 000000000012FB48    AddrReturn 0000000000000000
*** 122 called from 0000000000000000   STACK 000000000012FB50    AddrReturn 0000000000000000
*** 123 called from 0000000000000000   STACK 000000000012FB58    AddrReturn 0000000000000000
*** 124 called from 0000000000000000   STACK 000000000012FB60    AddrReturn 0000000000000000
*** 125 called from 0000000000000000   STACK 000000000012FB68    AddrReturn 0000000000000000
*** 126 called from 0000000000000000   STACK 000000000012FB70    AddrReturn 0000000000000000
*** 127 called from 0000000000000000   STACK 000000000012FB78    AddrReturn 0000000000000000
*** 128 called from 0000000000000000   STACK 000000000012FB80    AddrReturn 0000000000000000
*** 129 called from 0000000000000000   STACK 000000000012FB88    AddrReturn 0000000000000000
*** 130 called from 0000000000000000   STACK 000000000012FB90    AddrReturn 0000000000000000
*** 131 called from 0000000000000000   STACK 000000000012FB98    AddrReturn 0000000000000000
*** 132 called from 0000000000000000   STACK 000000000012FBA0    AddrReturn 0000000000000000
*** 133 called from 0000000000000000   STACK 000000000012FBA8    AddrReturn 0000000000000000
*** 134 called from 0000000000000000   STACK 000000000012FBB0    AddrReturn 0000000000000000
*** 135 called from 0000000000000000   STACK 000000000012FBB8    AddrReturn 0000000000000000
*** 136 called from 0000000000000000   STACK 000000000012FBC0    AddrReturn 0000000000000000
*** 137 called from 0000000000000000   STACK 000000000012FBC8    AddrReturn 0000000000000000
*** 138 called from 0000000000000000   STACK 000000000012FBD0    AddrReturn 0000000000000000
*** 139 called from 0000000000000000   STACK 000000000012FBD8    AddrReturn 0000000000000000
*** 140 called from 0000000000000000   STACK 000000000012FBE0    AddrReturn 0000000000000000
*** 141 called from 0000000000000000   STACK 000000000012FBE8    AddrReturn 0000000000000000
*** 142 called from 0000000000000000   STACK 000000000012FBF0    AddrReturn 0000000000000000
*** 143 called from 0000000000000000   STACK 000000000012FBF8    AddrReturn 0000000000000000
*** 144 called from 0000000000000000   STACK 000000000012FC00    AddrReturn 0000000000000000
*** 145 called from 0000000000000000   STACK 000000000012FC08    AddrReturn 0000000000000000
*** 146 called from 0000000000000000   STACK 000000000012FC10    AddrReturn 0000000000000000
*** 147 called from 0000000000000000   STACK 000000000012FC18    AddrReturn 0000000000000000
*** 148 called from 0000000000000000   STACK 000000000012FC20    AddrReturn 0000000000000000
*** 149 called from 0000000000000000   STACK 000000000012FC28    AddrReturn 0000000000000000
*** 150 called from 0000000000000000   STACK 000000000012FC30    AddrReturn 0000000000000000
*** 151 called from 0000000000000000   STACK 000000000012FC38    AddrReturn 0000000000000000
*** 152 called from 0000000000000000   STACK 000000000012FC40    AddrReturn 0000000000000000
*** 153 called from 0000000000000000   STACK 000000000012FC48    AddrReturn 0000000000000000
*** 154 called from 0000000000000000   STACK 000000000012FC50    AddrReturn 0000000000000000
*** 155 called from 0000000000000000   STACK 000000000012FC58    AddrReturn 0000000000000000
*** 156 called from 0000000000000000   STACK 000000000012FC60    AddrReturn 0000000000000000
*** 157 called from 0000000000000000   STACK 000000000012FC68    AddrReturn 0000000000000000
*** 158 called from 0000000000000000   STACK 000000000012FC70    AddrReturn 0000000000000000
*** 159 called from 0000000000000000   STACK 000000000012FC78    AddrReturn 0000000000000000
*** 160 called from 0000000000000000   STACK 000000000012FC80    AddrReturn 0000000000000000
*** 161 called from 0000000000000000   STACK 000000000012FC88    AddrReturn 0000000000000000
*** 162 called from 0000000000000000   STACK 000000000012FC90    AddrReturn 0000000000000000
*** 163 called from 0000000000000000   STACK 000000000012FC98    AddrReturn 0000000000000000
*** 164 called from 0000000000000000   STACK 000000000012FCA0    AddrReturn 0000000000000000
*** 165 called from 0000000000000000   STACK 000000000012FCA8    AddrReturn 0000000000000000
*** 166 called from 0000000000000000   STACK 000000000012FCB0    AddrReturn 0000000000000000
*** 167 called from 0000000000000000   STACK 000000000012FCB8    AddrReturn 0000000000000000
*** 168 called from 0000000000000000   STACK 000000000012FCC0    AddrReturn CCCCCCCCCCCCCCCC
*** 169 called from CCCCCCCCCCCCCCCC   STACK 000000000012FCC8    AddrReturn CCCCCCCCCCCCCCCC
*** 170 called from CCCCCCCCCCCCCCCC   STACK 000000000012FCD0    AddrReturn CCCCCCCCCCCCCCCC
*** 171 called from CCCCCCCCCCCCCCCC   STACK 000000000012FCD8    AddrReturn CCCCCCCCCCCCCCCC
*** 172 called from CCCCCCCCCCCCCCCC   STACK 000000000012FCE0    AddrReturn CCCCCCCCCCCCCCCC
*** 173 called from CCCCCCCCCCCCCCCC   STACK 000000000012FCE8    AddrReturn 0000000300000000
*** 174 called from 0000000300000000   STACK 000000000012FCF0    AddrReturn 0000000300000000
*** 175 called from 0000000300000000   STACK 000000000012FCF8    AddrReturn 0000000300000000
*** 176 called from 0000000300000000   STACK 000000000012FD00    AddrReturn 000000000012FCF0
*** 177 called from 000000000012FCF8   STACK 000000000012FD08    AddrReturn 0000000300000000
*** 178 called from 0000000300000000   STACK 000000000012FD10    AddrReturn 000000000012FD10
*** 179 called from 000000000012FD18   STACK 000000000012FD18    AddrReturn 0000000300000000
*** 180 called from 0000000300000000   STACK 000000000012FD20    AddrReturn 0000000000000000
*** 181 called from 0000000000000000   STACK 000000000012FD28    AddrReturn 0000000000000000
*** 182 called from 0000000000000000   STACK 000000000012FD30    AddrReturn 0000000000000000
*** 183 called from 0000000000000000   STACK 000000000012FD38    AddrReturn 0000000000000000
*** 184 called from 0000000000000000   STACK 000000000012FD40    AddrReturn 0000000000000000
*** 185 called from 0000000100000000   STACK 000000000012FD48    AddrReturn 0000000100000000
*** 186 called from 0000000000000000   STACK 000000000012FD50    AddrReturn 0000000000000000
*** 187 called from 0000000000000000   STACK 000000000012FD58    AddrReturn 0000000100000000
*** 188 called from 0000000100000000   STACK 000000000012FD60    AddrReturn 0000000000000000
*** 189 called from 0000000000000000   STACK 000000000012FD68    AddrReturn 0000000000000000
*** 190 called from 0000000000000000   STACK 000000000012FD70    AddrReturn 0000000000000000
*** 191 called from 0000000000000000   STACK 000000000012FD78    AddrReturn 0000000000000000
*** 192 called from 0000000000000000   STACK 000000000012FD80    AddrReturn 0000000000000000
*** 193 called from 0000000000000000   STACK 000000000012FD88    AddrReturn 0000000000000000
*** 194 called from 0000000000000000   STACK 000000000012FD90    AddrReturn 0000000000000000
*** 195 called from 0000000000000000   STACK 000000000012FD98    AddrReturn 0000000000000000
*** 196 called from 0000000000000000   STACK 000000000012FDA0    AddrReturn 0000000000000000
*** 197 called from 0000000000000000   STACK 000000000012FDA8    AddrReturn 0000000000000000
*** 198 called from 0000000000000000   STACK 000000000012FDB0    AddrReturn 0000000000000000
*** 199 called from 0000000000000000   STACK 000000000012FDB8    AddrReturn 0000000000000000
*** 200 called from 0000000000000000   STACK 000000000012FDC0    AddrReturn 0000000000000000
*** 201 called from 0000000000000000   STACK 000000000012FDC8    AddrReturn 0000000000000000
*** 202 called from 0000000000000000   STACK 000000000012FDD0    AddrReturn 0000000000000000
*** 203 called from 0000000000000000   STACK 000000000012FDD8    AddrReturn 0000000000000000
*** 204 called from 0000000000000000   STACK 000000000012FDE0    AddrReturn 0000000000000000
*** 205 called from 0000000000000000   STACK 000000000012FDE8    AddrReturn CCCCCCCCCCCCCCCC
*** 206 called from CCCCCCCCCCCCCCCC   STACK 000000000012FDF0    AddrReturn 000000CECCCCCCCC
*** 207 called from 000000CFCCCCCCCC   STACK 000000000012FDF8    AddrReturn CCCCCCCC00000001
*** 208 called from CCCCCCCC00000001   STACK 000000000012FE00    AddrReturn FFFFFFFFFFFFFFFE
*** 209 called from FFFFFFFFFFFFFFFE   STACK 000000000012FE08    AddrReturn CCCCCCCCCCCCCCCC
*** 210 called from CCCCCCCCCCCCCCCC   STACK 000000000012FE10    AddrReturn 000000000012FE40
*** 211 called from 000000000012FE40   STACK 000000000012FE18    AddrReturn 000000014000122F
*** 212 called from 000000014000122F   STACK 000000000012FE20    AddrReturn CCCCCCCCCCCCCCCC
*** 213 called from CCCCCCCCCCCCCCCC   STACK 000000000012FE28    AddrReturn CCCCCCCCCCCCCCCC
*** 214 called from CCCCCCCCCCCCCCCC   STACK 000000000012FE30    AddrReturn CCCCCCCCCCCCCCCC
*** 215 called from CCCCCCCCCCCCCCCC   STACK 000000000012FE38    AddrReturn CCCCCCCCCCCCCCCC
*** 216 called from CCCCCCCCCCCCCCCC   STACK 000000000012FE40    AddrReturn 000000000012FE70
*** 217 called from 000000000012FE70   STACK 000000000012FE48    AddrReturn 000000014000125F
*** 218 called from 000000014000125F   STACK 000000000012FE50    AddrReturn CCCCCCCCCCCCCCCC
*** 219 called from CCCCCCCCCCCCCCCC   STACK 000000000012FE58    AddrReturn CCCCCCCCCCCCCCCC
*** 220 called from CCCCCCCCCCCCCCCC   STACK 000000000012FE60    AddrReturn CCCCCCCCCCCCCCCC
*** 221 called from CCCCCCCCCCCCCCCC   STACK 000000000012FE68    AddrReturn CCCCCCCCCCCCCCCC
*** 222 called from CCCCCCCCCCCCCCCC   STACK 000000000012FE70    AddrReturn 000000000012FEA0
*** 223 called from 000000000012FEA0   STACK 000000000012FE78    AddrReturn 000000014000128F
*** 224 called from 000000014000128F   STACK 000000000012FE80    AddrReturn CCCCCCCCCCCCCCCC
*** 225 called from CCCCCCCCCCCCCCCC   STACK 000000000012FE88    AddrReturn CCCCCCCCCCCCCCCC
*** 226 called from CCCCCCCCCCCCCCCC   STACK 000000000012FE90    AddrReturn CCCCCCCCCCCCCCCC
*** 227 called from CCCCCCCCCCCCCCCC   STACK 000000000012FE98    AddrReturn CCCCCCCCCCCCCCCC
*** 228 called from CCCCCCCCCCCCCCCC   STACK 000000000012FEA0    AddrReturn 000000000012FED0
*** 229 called from 000000000012FED0   STACK 000000000012FEA8    AddrReturn 00000001400012CB
*** 230 called from 00000001400012CB   STACK 000000000012FEB0    AddrReturn CCCCCCCCCCCCCCCC
*** 231 called from CCCCCCCCCCCCCCCC   STACK 000000000012FEB8    AddrReturn CCCCCCCCCCCCCCCC
*** 232 called from CCCCCCCCCCCCCCCC   STACK 000000000012FEC0    AddrReturn CCCCCCCCCCCCCCCC
*** 233 called from CCCCCCCCCCCCCCCC   STACK 000000000012FEC8    AddrReturn CCCCCCCCCCCCCCCC
*** 234 called from CCCCCCCCCCCCCCCC   STACK 000000000012FED0    AddrReturn 0000000000000000
*** 235 called from 0000000000000000   STACK 000000000012FED8    AddrReturn 000000014000190C
*** 236 called from 000000014000190C   STACK 000000000012FEE0    AddrReturn 0000000100000001
*** 237 called from 0000000100000001   STACK 000000000012FEE8    AddrReturn 0000000000454B50
*** 238 called from 0000000000454B50   STACK 000000000012FEF0    AddrReturn 0000000000000000
*** 23

采纳答案by RED SOFT ADAIR

I finally found a reliable way to log the stack frames in x64, using the Windows function CaptureStackBackTrace(). As I did not want to update my SDK, I call it via GetProcAddress(LoadLibrary());

我终于找到了一种使用 Windows 函数在 x64 中记录堆栈帧的可靠方法CaptureStackBackTrace()。由于我不想更新我的 SDK,我通过调用它GetProcAddress(LoadLibrary());

   typedef USHORT (WINAPI *CaptureStackBackTraceType)(__in ULONG, __in ULONG, __out PVOID*, __out_opt PULONG);
   CaptureStackBackTraceType func = (CaptureStackBackTraceType)(GetProcAddress(LoadLibrary("kernel32.dll"), "RtlCaptureStackBackTrace"));

   if(func == NULL)
       return; // WOE 29.SEP.2010

   // Quote from Microsoft Documentation:
   // ## Windows Server 2003 and Windows XP:  
   // ## The sum of the FramesToSkip and FramesToCapture parameters must be less than 63.
   const int kMaxCallers = 62; 

   void* callers[kMaxCallers];
   int count = (func)(0, kMaxCallers, callers, NULL);
   for(i = 0; i < count; i++)
      printf(TraceFile, "*** %d called from %016I64LX\n", i, callers[i]);

回答by MSN

We use minidumps exclusively here. You can generate a stripped down one that just includes stack information and dump out a stack trace from a decent debugger later.

我们在这里专门使用小型转储。您可以生成一个仅包含堆栈信息的精简版,并稍后从合适的调试器中转储堆栈跟踪。

It doesn't solve your problem directly, but I think it will provide you a much better postmortem reporting mechanism.

它不能直接解决您的问题,但我认为它将为您提供更好的事后报告机制。

回答by MikeW

In Trial 3, you may be using CaptureStackBackTrace() incorrectly. According to the documentation, on Windows XP and Windows Server 2003, the sum of the first and second parameters must be less than 63, but, in your case, the sum would be 128.

在试用版 3 中,您可能错误地使用了 CaptureStackBackTrace()。根据文档,在 Windows XP 和 Windows Server 2003 上,第一个和第二个参数的总和必须小于 63,但在您的情况下,总和将为 128。

http://msdn.microsoft.com/en-us/library/windows/desktop/bb204633%28v=vs.85%29.aspx

http://msdn.microsoft.com/en-us/library/windows/desktop/bb204633%28v=vs.85%29.aspx

回答by Pedro Reis

For vs2008 x64: Based on https://msdn.microsoft.com/en-us/library/windows/desktop/bb204633%28v=vs.85%29.aspxand RED SOFT ADAIR:

对于 vs2008 x64:基于https://msdn.microsoft.com/en-us/library/windows/desktop/bb204633%28v=vs.85%29.aspx和 RED SOFT ADAIR:

#if defined DEBUG_SAMPLES_MANAGEMENT  

#include "DbgHelp.h"
#include <WinBase.h>
#pragma comment(lib, "Dbghelp.lib")

void printStack( void* sample_address, std::fstream& out )
{
    typedef USHORT (WINAPI *CaptureStackBackTraceType)(__in ULONG, __in ULONG, __out PVOID*, __out_opt PULONG);
    CaptureStackBackTraceType func = (CaptureStackBackTraceType)(GetProcAddress(LoadLibrary(L"kernel32.dll"), "RtlCaptureStackBackTrace"));

    if(func == NULL)
        return; // WOE 29.SEP.2010

    // Quote from Microsoft Documentation:
    // ## Windows Server 2003 and Windows XP:  
    // ## The sum of the FramesToSkip and FramesToCapture parameters must be less than 63.
    const int kMaxCallers = 62; 

    void         * callers_stack[ kMaxCallers ];
    unsigned short frames;
    SYMBOL_INFO  * symbol;
    HANDLE         process;
    process = GetCurrentProcess();
    SymInitialize( process, NULL, TRUE );
    frames               = (func)( 0, kMaxCallers, callers_stack, NULL );
    symbol               = ( SYMBOL_INFO * )calloc( sizeof( SYMBOL_INFO ) + 256 * sizeof( char ), 1 );
    symbol->MaxNameLen   = 255;
    symbol->SizeOfStruct = sizeof( SYMBOL_INFO );

    out << "(" << sample_address << "): " << std::endl;
    const unsigned short  MAX_CALLERS_SHOWN = 6;
    frames = frames < MAX_CALLERS_SHOWN? frames : MAX_CALLERS_SHOWN;
    for( unsigned int i = 0;  i < frames;  i++ )
    {
        SymFromAddr( process, ( DWORD64 )( callers_stack[ i ] ), 0, symbol );
        out << "*** " << i << ": " << callers_stack[i] << " " << symbol->Name << " - 0x" << symbol->Address << std::endl;
    }

    free( symbol );
}
#endif

Called here:

在这里调用:

#if defined DEBUG_SAMPLES_MANAGEMENT
        if(owner_ != 0)
        {   
            std::fstream& out = owner_->get_debug_file();
            printStack( this, out );   
        }
#endif

回答by Sam Ginrich

Found the short version with the "CaptureStackBackTraceType" really useful!

发现带有“CaptureStackBackTraceType”的简短版本真的很有用!

Then resolved function names of the "callers[]" using SymFromAddr(), SymInitialize(), which is mainly the version from Pedro Reis

然后使用SymFromAddr()SymInitialize()解析“ callers[]”的函数名称, 主要是来自 Pedro Reis 的版​​本

and finally demangled the function signatures according to function to mangle/demangle functions

最后根据function 对函数签名 进行 deangled 以 mangle/demangle 函数

NOTE: GNU demangler function abi::__cxa_demangle()expects a single underscore prefix

注意:GNU demangler 函数abi::__cxa_demangle()需要一个下划线前缀

回答by Ben Russell

When using StackWalk64you are iterating through the thread's entire stack whether there is valid data or not. Once you hit a return address of 0 you should terminate the walk, like so:

使用时,StackWalk64您正在遍历线程的整个堆栈,无论是否有有效数据。返回地址为 0 后,您应该终止遍历,如下所示:

for (ULONG Frame = 0; ; Frame++)
{
  if (FALSE == StackWalk64(...))
  {
    printf("Stack walk failed!\n");
    break;
  }  

  if (stackFrame.AddrPC.Offset == 0)
  {
    printf("Stack walk complete!\n");
    break;
  }

  do_something();
}

回答by Edouard A.

StackWalk64 is the right choice, the first call will give you the caller's address.

StackWalk64 是正确的选择,第一次调用会给你调用者的地址。

Your problem might be that in release you have a lot of inlining going on. The return address may not be what you expect.

你的问题可能是在发布时你有很多内联正在进行。退货地址可能不是您所期望的。

edit : you only need to set AddrPC and AddrFrame. Just make sure that your rbp and rip are the ones corresponding to your callee context.

编辑:您只需要设置 AddrPC 和 AddrFrame。只要确保您的 rbp 和 rip 是与您的被调用者上下文相对应的。

回答by Edouard A.

Regarding the first issue: disable "Omit stack frames" in thre release version, and the "trivial" stack tracing code will work.

关于第一个问题:在 thre release 版本中禁用“Omit stack frames”,“trivial”堆栈跟踪代码将起作用。

回答by Sam Deane

Regarding RtlCaptureStackBackTrace, one thing I've noticed on 32-bit Windows is that it fails if you pass too large a number into it for FramesToCapture. Experimentally I've identified 61 as the maximum value, for no reason that I can fathom!

关于 RtlCaptureStackBackTrace,我在 32 位 Windows 上注意到的一件事是,如果您为 FramesToCapture 传递太大的数字,它会失败。实验上我已经确定 61 为最大值,没有理由我能理解!

Not sure if it's the same in x64, but that might explain why you're getting no info out.

不确定它在 x64 中是否相同,但这可能解释了为什么您没有得到任何信息。

回答by KeRneL

Disassembling RtlCaptureStackBackTrace() I noticed that maximum value passed to RtlCaptureStackBackTrace() should be: framesToSkip+framesToCapture+1 should be less than 64. otherwise it returns 0 and there is no other error codes.

反汇编 RtlCaptureStackBackTrace() 我注意到传递给 RtlCaptureStackBackTrace() 的最大值应该是:framesToSkip+framesToCapture+1 应该小于 64。否则它返回 0 并且没有其他错误代码。