如何从jitted .Net函数的原始地址获取源代码信息?

时间:2018-02-28 16:34:48

标签: .net debugging profiling clr

我正在研究一个调试器,它应该在正在调试的进程的上下文中调用某个函数(例如,kernel32.dll!CreateFileW)时存储当前的堆栈跟踪。

调试器将一些代码注入进程,安装一个钩子。然后钩子使用RtlCaptureStackBackTrace获取堆栈跟踪并将其保存在某处。

然后,调试器使用函数SymFromAddr解析每个堆栈跟踪的条目。

它适用于非托管代码。

今天我尝试了这种方法,用于支持CLR的MFC应用程序。现在它是非托管代码。钩子仍然获得堆栈跟踪,但调试器无法解析某些堆栈条目。我猜这些条目属于JIT编译器生成的代码。

我对CLR个人资料工作者有点熟悉,可以收到JITCompilationStarted等通知。

问题是如何解决(即获取源文件名和行号)JIT编译器生成的代码地址?

我不能只调用DoStackSnapshot因为被挂钩的函数可以被调用很多时间,所以DoStackSnapshot会让这个过程变得懒散。

我可以使用FunctionEnter2 / FunctionLeave,但是当执行进入/离开函数时我们会调用它们,但我无法获得有关确切代码行的信息。

谢谢!

1 个答案:

答案 0 :(得分:1)

虽然它已明确说明,但听起来您的问题归结为从托管探查器内的指令指针获取源位置。

获取模块,元数据标记和IL偏移。

  1. 第一步是获取FunctionID,在大多数情况下,这已经给你了,但如果没有,你可以使用ICorProfilerInfo::GetFunctionFromIP

    从指令指针获取它LI>
  2. 接下来,您可以获取原生< - >通过将FunctionID传递给ICorProfilerInfo::GetILToNativeMapping来映射函数的IL。我依旧回忆起映射是按顺序返回的,所以你可以在这里执行二进制搜索。

  3. 将FunctionID传递到ICorProfilerInfo::GetFunctionInfo以获取ModuleID和方法元数据标记。

  4. 将ModuleID传递到ICorProfilerInfo3::GetModuleInfo2以获取路径。 IIRC,路径将通过name参数返回,但您应该检查pdwModuleFlags以确保模块存在于磁盘上,否则名称将无意义(例如,如果模块被解雇了。

  5. 获取文件名和行号。

    这是使用symbol store api执行的。我建议在监控应用程序或后处理步骤中执行此部分以避免占用分析器。

    1. 获取模块的IMetaDataImport。如果您是在分析器中执行此操作,则可以使用CorProfilerInfo::GetModuleMetaData;如果您不在分析器中,则可以使用IMetaDataDispenser

    2. 使用ISymUnmanagedBinder::GetReaderForFileISymUnmanagedReader::GetMethodISymUnmanagedMethod::GetSequencePoints获取IL< - >源映射。