我正在使用MSIL分析器,遇到接口问题ManagedToUnmanagedTransition和UnmanagedToManagedTransition回调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)和函数名称?
我在主要的CLR dll,mscorlib.dll中看到了它,我在这个CLR Profiling API接口ICorProfilerCallback2中看到了它.
只是好奇:'Cor'这个词代表什么?
我只想使用.NET Profiling API(ICorProfilerCallback等),但同时又不想处理C++.我一直在寻找一段时间,并且没有在C#中找到任何示例,但是C#+ C++中最有趣的部分是使用C++编写的.
我想写一个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框架的非托管API在进程中分析.NET进程时,是否可以查找与提供给StackSnapshotCallback函数的本机指令指针相关的IL指令指针?
很明显,我正在拍摄当前堆栈的快照,并希望在堆栈转储中提供文件和行号信息.该管理堆栈浏览器通过查询做到这一点ISymUnmanagedMethod::GetSequencePoints.这很好,但是序列点与偏移相关联,到目前为止我假设它们是从方法开头的偏移量(用中间语言).
在他的博客文章的后续评论中发表了一篇文章:基础知识和基础知识,David Broman表示这种映射可以使用ICorDebugCode::GetILToNativeMapping.但是,这并不理想,因为获取此接口需要从另一个调试器进程附加到我的进程.
我想避免这一步,因为我想继续能够在我拍摄这些快照时从visual studio调试器中运行我的应用程序.这样可以更轻松地单击输出窗口中的行号并转到相关代码.
功能是可能的....您可以在托管代码内部随意吐出行编号堆栈跟踪,唯一的问题是它是否可访问.此外,我不想使用System::Diagnostics::StackTrace或System::Environment::StackTrace功能,因为,出于性能原因,我需要延迟堆栈的实际转储....因此,为了以后节省方法名称和代码位置的解决成本是可取的..以及混合本机和托管帧的能力.
我一直在查看CLR Profiling API的一些文章,其中许多文章都讨论了调用SetILFunctionBody()来进行实际的IL重写; 但是,这些文章中没有一个实际上解释了您可以用来重写实际方法IL字节的确切内容.是否有一个非托管的库可以让我写IL,还是我必须自己写一个?
我正在写一个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) 我目前正在调试公司的CLR探查器(通过ASP.NET 4.7.3282.0,.NET Framework 4.7.2),并看到CLR卸载通用类但未调用ClassUnloadStarted回调的情况。
简而言之,我们的探查器根据ClassLoadStarted,ClassLoadFinished和ClassUnloadStarted回调跟踪基于ClassID的加载类。在某些时候,该类(及其相关模块)将被卸载,但相关类ID不会调用ClassUnloadStarted回调。因此,我们剩下一个停滞的ClassID,以为该类仍在加载。稍后,当我们尝试查询该ClassID时,CLR意外崩溃(因为它现在指向垃圾内存)。
我的问题,考虑以下详细情况:
我找不到有关此行为的任何文档或理由,特别是ClassUnloadStarted没有被调用。我也没有在CoreCLR代码中找到任何提示。在此先感谢您的帮助!
详细方案:
这是所讨论的类(IComparable(T)带有T=ClassFromModuleFoo):
System/IComparable`1<ClassFromModuleFoo>
Run Code Online (Sandbox Code Playgroud)
当应用程序运行时,在卸载了某些模块后,问题就会显现出来。
这是确切的加载/卸载回调流程,基于添加的调试打印:
System/IComparable'1(ClassFromModuleFoo)mscorlib 的类已加载。ClassFromModuleFoo将模块Foo 的class 加载到程序集#1中。IComparable和ClassFromModuleFoo再次加载,这一次是在组装#2。现在,每个类有两个实例:一个在装配#1中加载的Foo中,一个在装配#2中加载的Foo中。ClassUnloadStartedClassFromModuleFoo在程序集1中需要回调。ClassUnloadStarted以后任何时候都不会调用System/IComparable'1(ClassFromModuleFoo)程序集1(即使已卸载其模块且其ClassID指向现在已损坏的内存)。一些其他信息:
COR_PRF_DISABLE_ALL_NGEN_IMAGES到事件探查器事件掩码来禁用本机映像,认为它可能会影响ClassLoad *回调,但并没有任何区别。我验证mscorlib.dll了确实在加载而不是其本机映像。编辑:
多亏我非常聪明的同事,我才能够通过一个小示例项目来重现该问题,该项目通过加载和卸载AppDomains来模拟这种情况。在这里是:https :
//github.com/shaharv/dotnet/tree/master/testers/module-load-unload
崩溃发生在测试中的此类上,该类已被卸载,并且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) 我正在开发一个 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 成功),但是当调用修改后的方法时,我们会收到可怕的“公共语言运行时检测到无效程序”。例外,没有进一步的信息。
我尝试过的事情:
这让我相信分析 API 可能不支持向没有任何异常处理子句的方法添加新的异常处理子句。我很想听听您的其他想法以及如何解决此问题的任何想法。
以下是来自日志记录的一些信息 - * 是原始 IL。
EXPORTING IL:
Offset IL notes
0 0x28 call EnterScope …Run Code Online (Sandbox Code Playgroud) 我已经通过 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
我目前正在使用 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 …
我为.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