在Windows/64位/混合模式下快速捕获堆栈跟踪 [英] Fast capture stack trace on windows / 64-bit / mixed mode

查看:344
本文介绍了在Windows/64位/混合模式下快速捕获堆栈跟踪的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

就像大多数人可能知道的那样,从Windows api开始,并进一步深入神奇的汇编世界,这里有很多不同的机制来跟踪堆栈跟踪-让我在这里列出一些我已经研究过的链接.

Like most of you probably know there exists plenty of different mechanisms to walk stack traces, starting from windows api, and continuing further into depth of magical assembly world - let me list here some of links I've already studied.

首先,我要说一下我想对混合模式(托管和非托管)/64位+ AnyCPU应用程序以及所有Windows api的CaptureStackBackTrace进行内存泄漏分析的机制最适合我的需求,但是由于我已分析-它不支持托管代码堆栈遍历. 但是该函数API最接近我的需要(因为它还会计算回溯哈希-特定调用堆栈的唯一标识符).

For of all let me mention that I want to have mechanism of memory leak analysis of mixed mode (managed and unmanaged) / 64-bit + AnyCPU application and from all windows api's CaptureStackBackTrace is most suitable for my needs, but as I have analyzed - it does not support managed code stack walking. But that function API is closest to what I need (Since it also calculates back trace hash - unique identifier of particular call stack).

我排除了查找内存泄漏的不同方法- 我尝试过的大多数软件都崩溃了,或者运行不可靠,或者给出了不好的结果.

I've excluded different approaches of locating memory leaks - most of software which I have tried is either crashing or does not work unreliably, or gives bad results.

我也不希望重新编译现有软件并覆盖malloc/其他新机制-因为这是繁重的任务(我们拥有大量的dll,包含大量的代码).我也怀疑这不是我需要执行的一次性工作-问题会以1-2年的周期返回,具体取决于编码的对象和对象,因此我宁愿在应用程序本身中具有内置的内存泄漏检测功能(内存api挂钩),而不是一遍又一遍地与这个问题作斗争.

Also I don't want to recompile existing software and override malloc / new other mechanism - because it's heavy task (we have huge code base with a lot of dll's). Also I suspect this is not one time job which I need to perform - issue comes back with 1-2 year cycle, depending of who and what was coding, so I would prefer to have built-in memory leaks detection in application itself (memory api hooking) instead of fighting with this problem over and over again.

http://www.codeproject.com/Articles/11132/Walking-the-callstack

使用StackWalk64 Windows API函数,但不适用于托管代码.对我来说,对64位的支持也不是很清楚-我已经看到了64位问题的一些解决方法-我怀疑当在同一线程内完成堆栈遍历时,此代码无法完全正常工作.

Uses StackWalk64 windows API function, but does not work with managed code. Also 64 bit support is not fully clear to me - I have seen some walkaround for 64 bit problem - I suspect that this code does not fully work when stack walk is done within same thread.

然后存在一个流程黑客: http://processhacker.sourceforge.net/

Then there exists process hacker: http://processhacker.sourceforge.net/

还使用StackWalk64,但扩展了其回调函数(第7和第8个参数)以支持混合模式堆栈遍历. 在使用7/8回调函数进行了许多复杂操作之后,我设法达到了对StackWalk64的支持,同时还支持混合模式(将堆栈跟踪作为矢量捕获-其中每个指针都指向调用进行的程序集/dll位置). 但是,您可能会猜到-StackWalk64的性能不足以满足我的需求-即使使用C#端的简单消息框,应用程序也只是挂起"一段时间,直到正确启动为止.

Which also use StackWalk64, but extends it's call back function (7th and 8-th parameters) to support mixed mode stack walking. After a lot of complexities with 7/8 call back functions I've managed to reach also support of StackWalk64 with mixed mode support (Catching stack trace as vector - where each pointer refers to assembly / dll location where call went by). But as you may guess - the performance of StackWalk64 is insufficient for my needs - even with simple Message box from C# side, application simply "hangs" for a while until it starts up correctly.

CaptureStackBackTrace函数调用没有出现如此严重的延迟,因此我认为StackWalk64的性能不足以满足我的需求.

I haven't seen such heavy delays with CaptureStackBackTrace function call, so I assume that performance of StackWalk64 is insufficient for my needs.

还存在基于COM的堆栈跟踪确定方法-像这样: http://www.codeproject.com/Articles/371137/具有IDebugClient-Inter的混合模式Stackwalk

There exists also COM based approach of stack trace determination - like this: http://www.codeproject.com/Articles/371137/A-Mixed-Mode-Stackwalk-with-the-IDebugClient-Inter

http://blog.steveniemitz.com/building-a-混合模式堆栈行者第1部分

但是我担心的是-它需要COM,并且线程需要进行com初始化,并且由于内存api挂钩,我不应该触摸任何线程内的com状态,因为它会导致更严重的问题(例如,错误的单元号)初始化,其他故障)

but what I'm afraid of - it requires COM , and thread needs to be com initialized, and due to memory api hooking I should not touch com state within any thread, because it can results in heavier problems (e.g. incorrect apartment initialization, other glitches)

现在我已经达到了Windows API不足以满足我自己需要的程度,我需要手动遍历调用堆栈. 可以找到此类示例,例如:

Now I've reached the point when windows API becomes insufficient for my own needs, and I need to walk through call stack manually. Such examples can be found for example:

http://www.codeproject.com/Articles/11221/Easy-Detection内存泄漏 请参阅功能FillStackInfo/仅32位,不支持托管代码.

http://www.codeproject.com/Articles/11221/Easy-Detection-of-Memory-Leaks See function FillStackInfo / 32 bit only, does not support managed code.

关于反转堆栈跟踪有两点提及-例如在以下链接上:

There are couple of mentions about reversing stack trace - for example on following links:

  1. http://blog.airesoft. co.uk/2009/02/grabbing-kernel-thread-contexts-the-process-explorer-way/
  2. http://cbloomrants.blogspot.fi/2009 /01/01-30-09-stack-tracing-on-windows.html
  3. http://www.gamedev. net/topic/364861-stack-dump-on-win32-how-to-get-api-addresses/
  4. http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/
  1. http://blog.airesoft.co.uk/2009/02/grabbing-kernel-thread-contexts-the-process-explorer-way/
  2. http://cbloomrants.blogspot.fi/2009/01/01-30-09-stack-tracing-on-windows.html
  3. http://www.gamedev.net/topic/364861-stack-dump-on-win32-how-to-get-api-addresses/
  4. http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/

尤其是1、3、4个链接提供了一些有趣的夜间阅读. :-)

Especially 1, 3, 4 links give some interesting night reading. :-)

但是即使它们是相当有趣的机制,也没有一个完全有效的演示示例.

But even thus they are rather interesting mechanisms, there is no fully working demo example on any of them.

我想其中一个例子是Wine的dbghelp实现(Windows的Linux仿真器",用于Linux),它还显示了StackWalk64到底如何工作,但我怀疑它与DWARF2文件格式的可执行文件有很大的联系,因此与当前的Windows PE可执行文件格式.

I guess one of examples is Wine's dbghelp implementation (Windows "emulator" for linux), which also shows how exactly StackWalk64 works at the end, but I suspect that it's heavily bound to DWARF2 file format executable, so it's not identical to current windows PE executable file format.

有人能指出我实现堆栈行走的良好实现吗?它可以在64位体系结构上工作,并具有混合模式支持(可以跟踪本机和托管内存分配),而这完全限于寄存器/调用堆栈/代码分析. (1、3、4的组合实现)

Can someone pintpoint me to good implementation of stack walking, working on 64-bit architecture, with mixed mode support (can track native and managed memory allocations), which is bound purely in register / call stack / code analysis. (Combined implementations of 1, 3, 4)

有人与Microsoft开发团队有良好的联系,他们可能会回答这个问题吗?

Does someone has any good contact from Microsoft development team, who could potentially answer to this question ?

推荐答案

2015年9月1日-我找到了原始功能,该功能被流程黑客调用,而那个功能就是

9-1-2015 - I've located original function which gets called by process hacker, and that one was

C:\ Windows \ Microsoft.NET \ Framework64 \ v4.0.30319 \ mscordacwks.dll OutOfProcessFunctionTableCallback

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscordacwks.dll OutOfProcessFunctionTableCallback

它是源代码-在这里: https://github.com/dotnet/coreclr/blob/master/src/debug/daccess/fntableaccess.cpp

it's source code - which was here: https://github.com/dotnet/coreclr/blob/master/src/debug/daccess/fntableaccess.cpp

从那里开始,我拥有该源代码中大部分更改的所有者-Jan Kotas(jkotas@microsoft.com),并就此问题与他联系.

From there I have owner of most of changes in that source code - Jan Kotas (jkotas@microsoft.com) and contacted him about this problem.

From: Jan Kotas <jkotas@microsoft.com>
To: Tarmo Pikaro <tapika@yahoo.com> 
Sent: Friday, January 8, 2016 3:27 PM
Subject: RE: Fast capture stack trace on windows 64 bit / mixed mode...

...

The mscordacwks.dll is called mscordaccore.dll in CoreCLR / github repro. The VS project 
files are auto-generated for it during the build 
(\coreclr\bin\obj\Windows_NT.x64.Debug\src\dlls\mscordac\mscordaccore.vcxproj).
You should be able to build and debug CoreCLR to understand how it works.
...

From: Jan Kotas <jkotas@microsoft.com>
To: Tarmo Pikaro <tapika@yahoo.com> 
Sent: Saturday, January 9, 2016 2:02 AM
Subject: RE: Fast capture stack trace on windows 64 bit / mixed mode...

> I've tried to replace 
> C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscordacwks.dll dll loading 
> with C:\Prototyping\dotNet\coreclr-master\bin\obj\Windows_NT.x64.Debug\src\dlls\mscordac\Debug\mscordaccore.dll
> loading (just compiled), but if previously I could get mixed mode stack trace correctly:
> ...

mscordacwks.dll is tightly coupled with the runtime. You cannot mix and match them between runtimes.
What I meant is that you can use CoreCLR to understand how this works.

但是他随后推荐了这种对我有用的解决方案:

But then he recommended this solution which was working for me:

int CaptureStackBackTrace3(int FramesToSkip, int nFrames, PVOID* BackTrace, PDWORD pBackTraceHash)
{
    CONTEXT ContextRecord;
    RtlCaptureContext(&ContextRecord);

    UINT iFrame;
    for (iFrame = 0; iFrame < nFrames; iFrame++)
    {
        DWORD64 ImageBase;
        PRUNTIME_FUNCTION pFunctionEntry = RtlLookupFunctionEntry(ContextRecord.Rip, &ImageBase, NULL);

        if (pFunctionEntry == NULL)
            break;

        PVOID HandlerData;
        DWORD64 EstablisherFrame;
        RtlVirtualUnwind(UNW_FLAG_NHANDLER,
            ImageBase,
            ContextRecord.Rip,
            pFunctionEntry,
            &ContextRecord,
            &HandlerData,
            &EstablisherFrame,
            NULL);

        BackTrace[iFrame] = (PVOID)ContextRecord.Rip;
    }

    return iFrame;
}

此代码片段仍缺少回溯哈希计算,但这可以在以后添加.

This code snipet still is missing backtrace hash calculation, but this is something can can be added afterwards.

还很重要的一点是要注意,在调试此代码段时,应使用本机调试,而不是混合模式(默认情况下,C#项目使用混合模式),因为这会在某种程度上干扰调试器中的堆栈跟踪. (可以弄清楚这种失真的发生方式和原因)

It's very import also to note that when debugging this code snipet you should use native debugging, not mixed mode (C# project by default use mixed mode), because it somehow disturbs stack trace in debugger. (Something to figure out how and why such distortion happens)

仍然缺少一个难题:如何使符号解析完全抵制FreeLibrary/Jit代码的处理,但这是我仍然需要弄清楚的事情.

There is still one missing piece of puzzle - how to make symbol resolution fully resistant to FreeLibrary / Jit code dispose, but this is something I need to figure out still.

请注意,RtlVirtualUnwind很可能仅适用于64位体系结构,而不适用于arm或32位.

Please note that RtlVirtualUnwind will most probably work only on 64-bit architecture, not on arm or 32-bit.

另一个有趣的事情是,存在功能RtlCaptureStackBackTrace 它在某种程度上类似于Windows api函数CaptureStackBackTrace-但它们在某种程度上有所不同-至少在命名上有所不同.另外,如果您检查RtlCaptureStackBackTrace-它最终会调用RtlVirtualUnwind-您可以从Windows Research Kernel源代码进行检查

One more funny thing is that there exists function RtlCaptureStackBackTrace which somehow resembles windows api function CaptureStackBackTrace - but they somehow differ - at least by naming. Also if you check RtlCaptureStackBackTrace - it calls eventually RtlVirtualUnwind - you can check it from Windows Research Kernel source codes

RtlCaptureStackBackTrace
>
RtlWalkFrameChain
>
RtlpWalkFrameChain
>
RtlVirtualUnwind

但是我测试过的RtlCaptureStackBackTrace无法正常工作. 与上面的函数RtlVirtualUnwind不同.

But what I have tested RtlCaptureStackBackTrace does not works correctly. Unlike function RtlVirtualUnwind above.

有点神奇. :-)

我将在第2阶段的问题中继续此调查表-在此处:

I'll continue this questionnaire with phase 2 question - in here:

>解析托管和本机堆栈跟踪-哪个API使用吗?

这篇关于在Windows/64位/混合模式下快速捕获堆栈跟踪的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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