如何从 .Net 函数的原始地址获取源代码信息?
How to get source code information from a raw address of jitted .Net function?
我正在开发一个调试器,当某个函数(例如,kernel32.dll!CreateFileW)在被调试进程的上下文中被调用时,它应该存储当前堆栈跟踪。
调试器向进程中注入一些代码,安装一个钩子。然后钩子使用 RtlCaptureStackBackTrace 获取堆栈跟踪并将其保存在某处。
然后调试器使用函数SymFromAddr解析每个堆栈跟踪的条目。
它适用于非托管代码。
今天,我已经为使用 CLR 支持构建的 MFC 应用程序尝试了这种方法。现在是非托管代码。挂钩仍然获得堆栈跟踪,但调试器无法解析某些堆栈条目。我猜这些条目属于 JIT 编译器生成的代码。
我对 CLR 分析器比较熟悉,可以收到 JITCompilationStarted.
这样的通知
问题是如何解析(即获取源文件名和行号)JIT 编译器生成的代码的地址?
我不能只调用 DoStackSnapshot 因为被挂接的函数确实可以调用很多次,所以 DoStackSnapshot 会使进程变慢。
我可以使用 FunctionEnter2/FunctionLeave,但它们在执行 enters/leaves 函数时被调用,我无法获得有关确切代码行的信息。
谢谢!
虽然明确说明,但听起来您的问题归结为从托管探查器中的指令指针获取源位置。
正在获取模块、元数据令牌和 IL 偏移量。
第一步是获取FunctionID,在大多数情况下,这已经给你了,但如果没有,你可以使用ICorProfilerInfo::GetFunctionFromIP[=从指令指针中获取它19=]
接下来,您可以通过将 FunctionID 传递到 ICorProfilerInfo::GetILToNativeMapping 来获取函数的本机 <--> IL 映射。我依稀记得映射是按顺序返回的,所以你可以在这里执行二进制搜索。
将 FunctionID 传递到 ICorProfilerInfo::GetFunctionInfo 以获取 ModuleID 和方法元数据令牌。
将ModuleID传入ICorProfilerInfo3::GetModuleInfo2得到路径。 IIRC,路径将通过 name
参数返回,但您应该检查 pdwModuleFlags
以确保该模块存在于磁盘上,否则名称将没有意义(例如,如果模块被发出).
获取文件名和行号。
这是使用 symbol store api 执行的我建议在监视应用程序或 post-processing 步骤中执行此部分以避免阻止分析器。
获取模块的 IMetaDataImport。如果您不在探查器中,则可以使用 CorProfilerInfo::GetModuleMetaData if you are doing this from within the profiler or using IMetaDataDispenser。
使用 ISymUnmanagedBinder::GetReaderForFile, ISymUnmanagedReader::GetMethod and ISymUnmanagedMethod::GetSequencePoints 获取 IL <--> 源映射。
我正在开发一个调试器,当某个函数(例如,kernel32.dll!CreateFileW)在被调试进程的上下文中被调用时,它应该存储当前堆栈跟踪。
调试器向进程中注入一些代码,安装一个钩子。然后钩子使用 RtlCaptureStackBackTrace 获取堆栈跟踪并将其保存在某处。
然后调试器使用函数SymFromAddr解析每个堆栈跟踪的条目。
它适用于非托管代码。
今天,我已经为使用 CLR 支持构建的 MFC 应用程序尝试了这种方法。现在是非托管代码。挂钩仍然获得堆栈跟踪,但调试器无法解析某些堆栈条目。我猜这些条目属于 JIT 编译器生成的代码。
我对 CLR 分析器比较熟悉,可以收到 JITCompilationStarted.
这样的通知问题是如何解析(即获取源文件名和行号)JIT 编译器生成的代码的地址?
我不能只调用 DoStackSnapshot 因为被挂接的函数确实可以调用很多次,所以 DoStackSnapshot 会使进程变慢。
我可以使用 FunctionEnter2/FunctionLeave,但它们在执行 enters/leaves 函数时被调用,我无法获得有关确切代码行的信息。
谢谢!
虽然明确说明,但听起来您的问题归结为从托管探查器中的指令指针获取源位置。
正在获取模块、元数据令牌和 IL 偏移量。
第一步是获取FunctionID,在大多数情况下,这已经给你了,但如果没有,你可以使用ICorProfilerInfo::GetFunctionFromIP[=从指令指针中获取它19=]
接下来,您可以通过将 FunctionID 传递到 ICorProfilerInfo::GetILToNativeMapping 来获取函数的本机 <--> IL 映射。我依稀记得映射是按顺序返回的,所以你可以在这里执行二进制搜索。
将 FunctionID 传递到 ICorProfilerInfo::GetFunctionInfo 以获取 ModuleID 和方法元数据令牌。
将ModuleID传入ICorProfilerInfo3::GetModuleInfo2得到路径。 IIRC,路径将通过
name
参数返回,但您应该检查pdwModuleFlags
以确保该模块存在于磁盘上,否则名称将没有意义(例如,如果模块被发出).
获取文件名和行号。
这是使用 symbol store api 执行的我建议在监视应用程序或 post-processing 步骤中执行此部分以避免阻止分析器。
获取模块的 IMetaDataImport。如果您不在探查器中,则可以使用 CorProfilerInfo::GetModuleMetaData if you are doing this from within the profiler or using IMetaDataDispenser。
使用 ISymUnmanagedBinder::GetReaderForFile, ISymUnmanagedReader::GetMethod and ISymUnmanagedMethod::GetSequencePoints 获取 IL <--> 源映射。