如何在进程内将本机映射到 IL 指令指针
当使用 .NET 框架的非托管 API 在进程中分析 .NET 进程时,是否可以查找与提供给 StackSnapshotCallback 函数的本机指令指针相关的 IL 指令指针?
很明显,我正在拍摄当前堆栈的快照,并希望在堆栈转储中提供文件和行号信息。 Managed Stack Explorer 通过查询 ISymUnmanagementMethod::GetSequencePoints 来完成此操作。 这很棒,但是序列点与偏移量相关联,到目前为止我假设这些是从方法开头的偏移量(用中间语言)。
在他的博客文章的后续评论中 分析器堆栈遍历:基础知识及其他,David Broman 表示可以使用 ICorDebugCode::GetILToNativeMapping
。 但是,这并不理想,因为获取此接口需要从另一个调试器进程附加到我的进程。
我想避免该步骤,因为我希望在拍摄这些快照时能够继续从 Visual Studio 调试器中运行我的应用程序。 这样可以更轻松地单击输出窗口中的行号并转到相关代码。
该功能是可能的......您可以在托管代码内随意吐出行编号的堆栈跟踪,唯一的问题是它是否可以访问。 另外,我不想使用 System::Diagnostics::StackTrace
或 System::Environment::StackTrace
功能,因为出于性能原因,我需要延迟堆栈的实际转储......因此节省了稍后解析方法名称和代码位置的成本......以及混合本机和托管帧的能力。
When using the unmanaged API for the .NET framework to profile a .NET process in-process, is it possible to look up the IL instruction pointer that correlates to the native instruction pointer provided to the StackSnapshotCallback function?
As is probably obvious, I am taking a snapshot of the current stack, and would like to provide file and line number information in the stack dump. The Managed Stack Explorer does this by querying ISymUnmanagedMethod::GetSequencePoints
. This is great, but the sequence points are associated to offsets, and I have so far assumed these are offsets from the beginning of the method ( in intermediate language ).
In a follow-up comment to his blog post Profiler stack walking: Basics and beyond, David Broman indicates that this mapping can be achieved using ICorDebugCode::GetILToNativeMapping
. However, this is not ideal as getting this interface requires attaching to my process from another, debugger process.
I would like to avoid that step because I would like to continue to be able to run my application from within the visual studio debugger while I am taking these snapshots. It makes it easier to click on the line number in the output window and go to the code in question.
The functionality is possible.... you can spit out a line-numbered stack trace at will inside of managed code, the only question, is it accessible. Also, I don't want to use the System::Diagnostics::StackTrace
or System::Environment::StackTrace
functionality because, for performance reasons, I need to delay the actual dump of the stack.... so saving the cost for resolution of method names and code location for later is desirable... along with the ability to intermix native and managed frames.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
为了将
ICorProfilerInfo2::DoStackSnapshot
提供的本机指令指针转换为中间语言方法偏移量,您必须执行两个步骤,因为DoStackSnapshot
提供了FunctionID
和本机指令指针作为虚拟内存地址。步骤1,是将指令指针转换为本机代码方法偏移量。 (距 JITed 方法开头的偏移量)。 这可以通过
ICorProfilerInfo2::GetCodeInfo2
步骤 2 来完成。一旦获得了距 natvie 代码方法开头的偏移量,您就可以使用它来转换为距中间语言方法开头的偏移量使用
ICorProfilerInfo2::GetILToNativeMapping
。然后,可以使用符号 API 将代码位置映射到文件和行号,
感谢 Mithun Shanbhag 寻求解决方案的指导。
In order to translate from a native instruction pointer as provided by
ICorProfilerInfo2::DoStackSnapshot
to an intermediate language method offset, you must take two steps sinceDoStackSnapshot
provides aFunctionID
and native instruction pointer as a virtual memory address.Step 1, is to convert the instruction pointer to a native code method offset. ( an offset from the beginning of the JITed method). This can be done with
ICorProfilerInfo2::GetCodeInfo2
Step 2. Once you have an offset from the begining of the natvie code method, you can use this to convert to an offset from the begining of the intermediate language method using
ICorProfilerInfo2::GetILToNativeMapping
.This can then be used to map the code location to a file and line number using the symbol APIs
Thanks to Mithun Shanbhag for direction in finding the solution.
确保您的构建生成符号。
扩展讨论:
鉴于此 - 看起来您不附加到流程的唯一原因是您可以在开发工具时轻松调试工具或其部分。 IMO 是不选择更好的设计(ICorDebug 或 w/e)的糟糕借口。 其设计不佳的原因是因为您的代码在(可能是)外部二进制文件的进程空间中执行,从而在已知(或更糟 - 未知)损坏的进程状态中导致令人讨厌的(“有时”罕见)副作用(包括损坏其他人的数据)。 一开始这应该足够了,但即使如此,也存在一些带有多线程代码的边缘情况等,需要解决设计问题。
大多数人通常会问“你到底想做什么?” 作为对过于复杂的做事方式的回应。 在大多数情况下,有一种更简单/更容易的方法。 在为本机代码编写了堆栈跟踪器之后,我知道它可能会变得混乱。
现在也许你最终会让一切正常,所以 - 只是我的 $.02
Make sure your build generates symbols.
Expanding on the discussion:
Given this - It looks like the only reason you're not attaching to process is so that you can debug your tool , or parts of it , easily, as you're developing it. That IMO is a poor excuse for not choosing a better design (ICorDebug or w/e ) when its available. The reason its poor design is because your code executes in the process space of (presumably) external binaries , causing nasty ('sometimes' rare) side effects (including corrupting somebody else data) in known (or worse - unknown) corrupt process states. That should be enough to begin with, but even otherwise, there are several edge cases with multi-threaded code, etc where the design needs to be worked around.
Most people generally ask "What are you really trying to do?" as a reply to an overtly complex way of doing things. In most cases there is a simpler/easier way. Having written a stack tracer for native code, I know it can get messy.
Now maybe you might end up making everything work , so - Just my $.02