标签: clr-profiling-api

分析动态pinvoke

我正在使用MSIL分析器,遇到接口问题ManagedToUnmanagedTransitionUnmanagedToManagedTransition回调ICorProfilerCallback.

我想要检索的是有关被调用方法的信息(它所在的名称和模块名称).

到目前为止它工作正常.直到所谓的动态pinvoke发生(详见:http://blogs.msdn.com/b/jonathanswift/archive/2006/10/03/dynamically-calling-an-unmanaged-dll-from-.net-_2800_c_23002900_ .aspx)

在这种情况下IMetaDataImport::GetPinvokeMap失败.还IMetaDataAssemblyImport::GetAssemblyProps返回"dynamic_pinvoke"作为程序集的名称.

profiler_1_0->GetTokenAndMetaDataFromFunction(function_id, IID_IMetaDataImport, (IUnknown**) &imd_import, &md_token);
imd_import->GetPinvokeMap(md_token, &mapping, module_name, buffer_size, &chars_read, &md_module_ref);
// here the fail occurs

profiler_1_0->GetTokenAndMetaDataFromFunction(function_id, IID_IMetaDataAssemblyImport, (IUnknown**) &imd_assembly_import, &md_token);
imd_assembly_import->GetAssemblyFromScope(&md_assembly);
imd_assembly_import->GetAssemblyProps(md_assembly, 0, 0, 0, assembly_name, buffer_size, &chars_read, 0, 0);
// assembly_name is set to "dynamic_pinvoke"
Run Code Online (Sandbox Code Playgroud)

如何通过动态pinvoke获取模块名称(.dll)和函数名称?

c++ pinvoke cil clr-profiling-api

62
推荐指数
1
解决办法
1855
查看次数

'Cor'代表什么?

我在主要的CLR dll,mscorlib.dll中看到了它,我在这个CLR Profiling API接口ICorProfilerCallback2中看到了它.

只是好奇:'Cor'这个词代表什么?

clr clr-profiling-api

22
推荐指数
2
解决办法
4843
查看次数

是否可以直接使用C#中的Profiling API?

我只想使用.NET Profiling API(ICorProfilerCallback等),但同时又不想处理C++.我一直在寻找一段时间,并且没有在C#中找到任何示例,但是C#+ C++中最有趣的部分是使用C++编写的.

.net c# api profiling clr-profiling-api

20
推荐指数
1
解决办法
4908
查看次数

CLR分析器:使用DefineAssemblyRef时出现问题

我想写一个CLR分析器来挂钩我们的应用程序功能GetILFunctionBody/SetILFunctionBody.

我想使用DefineAssemblyRef来导入我们的c#dll(用于IL代码),在这段代码中,DefineAssemblyRef总是返回True?我的dll必须签名吗?是否需要在全局程序集缓存(GAC)中安装?

     HRESULT CProfilerCallback::JITCompilationStarted
        (
        UINT functionId,
        BOOL fIsSafeToBlock
        )
    {
        ClassID classID;
        ModuleID moduleID;
        mdToken token;
        wchar_t wszClass[512];
        wchar_t wszMethod[512];
        HRESULT result = S_OK;
        ClassID classId = 0;
        ModuleID moduleId = 0;
        mdToken tkMethod = 0;

        // Get the moduleID and tkMethod    
        m_pICorProfilerInfo->GetFunctionInfo(functionId, &classId, &moduleId, &tkMethod);

        if(!GetMethodNameFromFunctionId(functionId,wszClass,wszMethod))
        {return S_FALSE;}


        if(wcscmp(wszMethod,L"FunctionName") == 0)
        {
            // Get the metadata import
            IMetaDataImport* pMetaDataImport = NULL;
            DebugBreak();
            result = m_pICorProfilerInfo->GetModuleMetaData
                (
                moduleId,
                ofRead, 
                IID_IMetaDataImport,
                (IUnknown** )&pMetaDataImport
                );


            if (FAILED(result)) …
Run Code Online (Sandbox Code Playgroud)

.net c# hook window clr-profiling-api

19
推荐指数
1
解决办法
831
查看次数

如何将本机映射到IL指令指针进程中

当使用.NET框架的非托管API在进程中分析.NET进程时,是否可以查找与提供给StackSnapshotCallback函数的本机指令指针相关的IL指令指针?

很明显,我正在拍摄当前堆栈的快照,并希望在堆栈转储中提供文件和行号信息.该管理堆栈浏览器通过查询做到这一点ISymUnmanagedMethod::GetSequencePoints.这很好,但是序列点与偏移相关联,到目前为止我假设它们是从方法开头的偏移量(用中间语言).

在他的博客文章的后续评论中发表了一篇文章:基础知识和基础知识,David Broman表示这种映射可以使用ICorDebugCode::GetILToNativeMapping.但是,这并不理想,因为获取此接口需要从另一个调试器进程附加到我的进程.

我想避免这一步,因为我想继续能够在我拍摄这些快照时从visual studio调试器中运行我的应用程序.这样可以更轻松地单击输出窗口中的行号并转到相关代码.

功能是可能的....您可以在托管代码内部随意吐出行编号堆栈跟踪,唯一的问题是它是否可访问.此外,我不想使用System::Diagnostics::StackTraceSystem::Environment::StackTrace功能,因为,出于性能原因,我需要延迟堆栈的实际转储....因此,为了以后节省方法名称和代码位置的解决成本是可取的..以及混合本机和托管帧的能力.

.net profiling clr-profiling-api

11
推荐指数
1
解决办法
1504
查看次数

我是否需要编写自己的非托管IL库来使用CLR Profiling API重写IL?

我一直在查看CLR Profiling API的一些文章,其中许多文章都讨论了调用SetILFunctionBody()来进行实际的IL重写; 但是,这些文章中没有一个实际上解释了您可以用来重写实际方法IL字节的确切内容.是否有一个非托管的库可以让我写IL,还是我必须自己写一个?

.net profiling cil rewriting clr-profiling-api

7
推荐指数
1
解决办法
758
查看次数

CLR概要分析:在catch块内抛出后的DoStackSnapshot会产生错误的指令指针

我正在写一个CLR分析器,我遇到了一些非常奇怪的东西.当抛出两个不同的异常时,一个来自try子句,一个来自catch子句,CLR通知我相同的指令指针.更具体地说:我已注册接收ExceptionThrown回调

virtual HRESULT STDMETHODCALLTYPE ExceptionThrown(ObjectID thrownObjectId);

在回调中,我在当前线程上启动DoStackSnapshot(https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/profiling/icorprofilerinfo2-dostacksnapshot-method).CLR为每一帧调用我的方法:

HRESULT stackSnapshotCallback(FunctionID funcId, UINT_PTR ip, COR_PRF_FRAME_INFO, ULONG32, BYTE context[], void *clientData)

但是,如果我从try子句和相应的catch子句抛出异常(代码示例如下),我会收到两者的SAME ip.我还要提到,这不是重新抛出的情况,当这是预期的时候,但是一个全新的异常甚至可能发生在catch的调用堆栈中.

在研究了更多内容并深入挖掘CoreCLR代码之后,我找不到发生这种情况的原因,这就是为什么我在这里问这个问题.我还要提到,在普通的C#调试器中,这很容易重现,我觉得这很令人震惊.我使用过.Net Framework 4.5,但这也发生在4.6和4.7上.

我相信,如果我理解为什么以下C#代码以这种方式运行,我可能会理解为什么CLR也会这样做.

这段代码:

try
{
    try
    {
        throw new Exception("A");
    }
    catch (Exception)
    {
        StackTrace st = new StackTrace(true);
        StackFrame sf = st.GetFrame(0);
        Console.WriteLine("Inside catch, instruction: " + sf.GetILOffset() + ". line: " + sf.GetFileLineNumber());
        throw new Exception("B");
    }
}
catch (Exception)
{
    StackTrace st = new StackTrace(true);
    StackFrame sf = st.GetFrame(0);
    Console.WriteLine("Outer catch, instruction: " …
Run Code Online (Sandbox Code Playgroud)

.net c# clr clr-profiling-api

7
推荐指数
1
解决办法
245
查看次数

即使类已卸载,也不会为通用类调用ICorProfilerCallback :: ClassUnloadStarted

我目前正在调试公司的CLR探查器(通过ASP.NET 4.7.3282.0,.NET Framework 4.7.2),并看到CLR卸载通用类但未调用ClassUnloadStarted回调的情况。

简而言之,我们的探查器根据ClassLoadStartedClassLoadFinishedClassUnloadStarted回调跟踪基于ClassID的加载。在某些时候,该类(及其相关模块)将被卸载,但相关类ID不会调用ClassUnloadStarted回调。因此,我们剩下一个停滞的ClassID,以为该类仍在加载。稍后,当我们尝试查询该ClassID时,CLR意外崩溃(因为它现在指向垃圾内存)。

我的问题,考虑以下详细情况:

  • 为什么不为我的(通用)类调用ClassUnloadStarted?
  • 这是CLR的预期的极端情况行为,还是CLR /分析API错误?

我找不到有关此行为的任何文档或理由,特别是ClassUnloadStarted没有被调用。我也没有在CoreCLR代码中找到任何提示。在此先感谢您的帮助!

详细方案:

这是所讨论的类(IComparable(T)带有T=ClassFromModuleFoo):

System/IComparable`1<ClassFromModuleFoo>
Run Code Online (Sandbox Code Playgroud)

当应用程序运行时,在卸载了某些模块后,问题就会显现出来。
这是确切的加载/卸载回调流程,基于添加的调试打印:

  1. System/IComparable'1(ClassFromModuleFoo)mscorlib 的类已加载。
  2. 之后,立即ClassFromModuleFoo将模块Foo 的class 加载到程序集#1中。
  3. Foo模块完成加载到部件1中。
  4. 然后,模块Foo再次装入另一个组件#2。
  5. IComparableClassFromModuleFoo再次加载,这一次是在组装#2。现在,每个类有两个实例:一个在装配#1中加载的Foo中,一个在装配#2中加载的Foo中。
  6. 模块Foo开始从部件#1卸载。
  7. ClassUnloadStartedClassFromModuleFoo在程序集1中需要回调。
  8. Foo模块完成了从组件#1卸载的工作。
  9. ClassUnloadStarted以后任何时候都不会调用System/IComparable'1(ClassFromModuleFoo)程序集1(即使已卸载其模块且其ClassID指向现在已损坏的内存)。

一些其他信息:

  • 该问题还会在最新的.NET Framework版本4.8 Preview中重现。
  • 我已通过添加COR_PRF_DISABLE_ALL_NGEN_IMAGES到事件探查器事件掩码来禁用本机映像,认为它可能会影响ClassLoad *回调,但并没有任何区别。我验证mscorlib.dll了确实在加载而不是其本机映像。

编辑:

多亏我非常聪明的同事,我才能够通过一个小示例项目来重现该问题,该项目通过加载和卸载AppDomains来模拟这种情况。在这里是:https :
//github.com/shaharv/dotnet/tree/master/testers/module-load-unload

崩溃发生在测试中的此类上,该类已被卸载,并且CLR没有针对该类调用卸载回调: …

.net generics clr profiling clr-profiling-api

7
推荐指数
1
解决办法
300
查看次数

ICorProfilerCallback2:CLR 分析器不会记录所有离开调用

我正在尝试编写一个分析器来记录进程中的所有 .Net 方法调用。目标是使其具有高性能,并将最后 5-10 分钟保留在内存中(固定缓冲区,循环覆盖旧信息),直到用户触发将该信息写入磁盘。预期用途是追踪很少重现的性能问题。

我从https://github.com/appneta/SimpleCLRProfiler的 SimpleCLRProfiler 项目开始。探查器利用.Net 探查的ICorProfilerCallback2回调接口。我让它在我的环境(Win 8.1、.Net 4.5、VS2012)中编译和工作。但是,我注意到有时会丢失记录了 Enter 呼叫的 Leave 呼叫。Console.WriteLine 调用的示例(我将 DbgView 的输出减少到理解所需的最低限度):

Line 1481: Entering System.Console.WriteLine
Line 1483: Entering SyncTextWriter.WriteLine
Line 1485: Entering System.IO.TextWriter.WriteLine
Line 1537: Leaving SyncTextWriter.WriteLine
Run Code Online (Sandbox Code Playgroud)

两个 Entering 呼叫没有对应的 Leaveing 呼叫。分析后的 .Net 代码如下所示:

Console.WriteLine("Hello, Simple Profiler!");
Run Code Online (Sandbox Code Playgroud)

相关的 SimpleCLRProfiler 方法是:

HRESULT CSimpleProfiler::registerGlobalCallbacks() 
{
   HRESULT hr = profilerInfo3->SetEnterLeaveFunctionHooks3WithInfo(
      (FunctionEnter3WithInfo*)MethodEntered3, 
      (FunctionEnter3WithInfo*)MethodLeft3, 
      (FunctionEnter3WithInfo*)MethodTailcall3);

   if (FAILED(hr))
      Trace_f(L"Failed to register global callbacks (%s)", _com_error(hr).ErrorMessage());

   return S_OK;
}

void CSimpleProfiler::OnEnterWithInfo(FunctionID functionId, COR_PRF_ELT_INFO eltInfo)
{
    MethodInfo info; …
Run Code Online (Sandbox Code Playgroud)

.net c# windows performance clr-profiling-api

5
推荐指数
1
解决办法
474
查看次数

使用.NET的ICorProfilerInfo::SetILFunctionBody,是否可以向没有任何异常处理的方法添加try-finally EH子句?

我正在开发一个 IL 重写分析器,我的目标是能够向方法添加 try-finally 块。本质上:

// IL to set some state 
try {
   // original IL 
} finally { 
   // IL to revert state
}
Run Code Online (Sandbox Code Playgroud)

根据分析 API ( https://msdn.microsoft.com/en-us/library/ms232096.aspx ) 的有限文档和信息,似乎应该能够使用 SetILFunctionBody 添加新的异常处理子句。

我一直在关注来自http://clrprofiler.codeplex.com/SourceControl/list/changesets?branch=master的 Microsoft 示例 ILRewrite 探查器。我添加了代码以将“EHCLause”添加到“ILRewriter”类维护的 EHCLause 列表中,并添加了适当的 left.s 和 endfinally IL 指令。从探查器的角度来看,一切似乎都正常(SetILFunctionBody 成功),但是当调用修改后的方法时,我们会收到可怕的“公共语言运行时检测到无效程序”。例外,没有进一步的信息。

我尝试过的事情:

  • 检查了仪器,代码没有在保护区内做非法的事情(例如返回或分支到外部)。
  • 如果我删除 EHCLause 和 left.s/endfinally 指令,则仪表化方法运行良好。
  • 我在 ILRewriting 代码中添加了大量日志记录,以在末尾转储修改后的 IL、EH 信息和字节。我使用所需的 try-finally 和状态跟踪代码制作了类似的方法,并且两种方法(检测与编译)的 IL 是相同的。然而,实际的“导出”字节有很大不同。

这让我相信分析 API 可能不支持向没有任何异常处理子句的方法添加新的异常处理子句。我很想听听您的其他想法以及如何解决此问题的任何想法。


以下是来自日志记录的一些信息 - * 是原始 IL。

EXPORTING IL:
Offset IL   notes
0   0x28    call EnterScope …
Run Code Online (Sandbox Code Playgroud)

.net c# profiler clr-profiling-api

5
推荐指数
1
解决办法
464
查看次数

.NET 检测 - 对自定义程序集的函数调用失败 - Azure Web 应用

我已经通过 Visual Studio 2012 将我的 .NET 检测分析器部署到 Azure webapps 中。我的分析器执行字节码检测,如下所示,

FunctionA()
{
   --> Injected C# function Call 
   functionA's body
   -->Injected C# function Call
}
Run Code Online (Sandbox Code Playgroud)

注入的函数调用驻留在单独的程序集 dll 上。在物理框中,程序集将添加到 GAC 中。但在 Azure 中,它将出现在 web 应用程序位置的文件夹中,该文件夹将在 web.config 文件中进行探测。

使用 IMetaDataAssemblyEmit 的 DefineAssemblyRef,我定义了程序集及其在加载到进程中的每个模块中的功能。该问题是注入的函数调用仅适用于Web应用程序模块的功能..!System.Web.dll 或 System.Data.dll 等其他模块无法调用该函数,这导致 Azure Web 应用程序无法加载并出现 502 错误。

很快,注入到 Web 应用程序以外的模块中就失败了。我猜这是加载自定义程序集时的安全问题,我也尝试设置[assembly: System.Security.AllowPartiallyTrustedCallers]PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]其他一些安全属性.. 没有帮助.. 如何使这个帮助程序集由 .Net 模块加载。?我是否需要为程序集设置任何其他特定的安全属性才能加载..?

profiler azure .net-assembly azure-web-app-service clr-profiling-api

5
推荐指数
0
解决办法
121
查看次数

理解结构的“this”参数(特别是迭代器/异步)

我目前正在使用 Profiler API 检查 CLR 中的深层对象。我在分析迭代器/异步方法的“this”参数(由编译器生成,形式为<name>d__123::MoveNext)时遇到了一个具体问题。

在研究这个时,我发现确实有一种特殊的行为。首先,C# 编译器将这些生成的方法编译为结构体(仅在 Release 模式下)。ECMA-334(C# 语言规范,第 5 版:https : //www.ecma-international.org/publications/files/ECMA-ST/ECMA-334.pdf)指出(12.7.8 此访问):

“...如果方法或访问器是迭代器或异步函数,则 this 变量表示调用该方法或访问器的结构的副本,....”

这意味着与其他“this”参数不同,在这种情况下,“this”是按值发送的,而不是按引用发送。我确实看到副本没有在外面修改。我试图了解结构实际上是如何发送的。

我冒昧地剥离了复杂的案例,并用一个小结构复制了它。看下面的代码:

struct Struct
    {
        public static void mainFoo()
        {
            Struct st = new Struct();
            st.a = "String";
            st.p = new Program();
            System.Console.WriteLine("foo: " + st.foo1());
            System.Console.WriteLine("static foo: " + Struct.foo(st));
        }

        int i;
        String a;
        Program p;

        [MethodImplAttribute(MethodImplOptions.NoInlining)]
        public static int foo(Struct st)
        {
            return st.i;
        }

        [MethodImplAttribute(MethodImplOptions.NoInlining)]
        public int foo1()
        {
            return i;
        }
    }
Run Code Online (Sandbox Code Playgroud)

NoInlining …

c# clr cil clr-profiling-api

5
推荐指数
1
解决办法
160
查看次数

为什么探测器不能附加?

我为.NET应用程序编写了一个小型分析器.它使用ICorProfilerCallback2界面.

分析器附加并适用于.NET 2.0应用程序,但不适用于.NET> 2.0(3.0,3.5,4.0).当我启动使用.NET 4.0编译的exe时没有任何反应,但是对于.NET 2.0,启动程序启动.我在运行托管exe之前设置了以下变量

@Echo off
set Cor_Enable_Profiling=0x1
set COR_PROFILER={67D8965A-8686-2639-9C24-E1F7D13EE105}
set COR_PROFILER_DLL=e:\Debug\Profiler.dll
set COR_PROFILER_PATH=e:\Debug\Profiler.dll
Run Code Online (Sandbox Code Playgroud)

知道为什么会这样吗?它甚至没有进入DllMain

.net profiler clr-profiling-api

3
推荐指数
1
解决办法
643
查看次数