查找.NET / CLR方法的所有上游调用方

时间:2013-09-13 20:27:18

标签: .net cil

我想通过多个程序集找出特定方法的所有上游调用者。

我不需要解析后期绑定引用或虚方法调用,简单直接的CIL call引用就可以了。

我看了几个选项:

  • 反射器:工具的分析器部分不作为扩展点公开。
  • FxCop:CallGraph类需要运行FxCop上下文。
  • Roslyn:我不知道从哪里开始,但无论如何我对从源码开始不感兴趣,我想给它一个程序集并使用字节码和元数据代替。
  • VS加载项:与Reflector一样,调用层次结构工具不会向加载项公开。

我想我的唯一解决方案是通过迭代程序集中的每个方法来向后工作,查找我的源方法的call指令,然后递归地为每个调用方法重复该过程。

假设我提出的解决方案是可行的方法,那么最好的方法是什么? MethodInfo.GetMethodBody().GetILAsByteArray()似乎有点硬。是否有任何库使得使用CIL(如ASM for Java)变得简单?

2 个答案:

答案 0 :(得分:2)

您可以使用Mono Cecil。为此,它与反射基本相同,除了它还为你解析方法体。

执行此操作的代码草图:

var assembly = AssemblyDefinition.ReadAssembly(assemblyPath);
var methods = from module in assembly.Modules
              from type in module.Types
              from method in type.Methods
              from instruction in method.Body.Instructions
              where instruction.OpCode == OpCodes.Call
                    || instruction.OpCode == OpCodes.Callvirt
              let calledMethod = (MethodReference)instruction.Operand
              where calledMethod.DeclaringType.Name == givenMethodTypeName
                    && calledMethod.Name == givenMethodName
              select method;

答案 1 :(得分:-1)

我建议使用Roslyn。 以前从StackOverflow链接的是svick在MSDN上的答案: http://social.msdn.microsoft.com/Forums/vstudio/en-US/85a816cb-e931-4b49-893a-abbbf38c7a38/can-i-get-function-callercallee-information-from-roslyn

这是副本svick的答案:     var syntaxTree = SyntaxTree.ParseCompilationUnit(code);

var semanticModel = Compilation.Create("compilation")
    .AddSyntaxTrees(syntaxTree)
    .AddReferences(new AssemblyFileReference(typeof(object).Assembly.Location))
    .GetSemanticModel(syntaxTree);

var baz = syntaxTree.Root
    .DescendentNodes()
    .OfType<ClassDeclarationSyntax>()
    .Single(m => m.Identifier.ValueText == "C1")
    .ChildNodes()
    .OfType<MethodDeclarationSyntax>()
    .Single(m => m.Identifier.ValueText == "Baz");

var bazSymbol = semanticModel.GetDeclaredSymbol(baz);

var invocations = syntaxTree.Root
    .DescendentNodes()
    .OfType<InvocationExpressionSyntax>();

var bazInvocations = invocations
    .Where(i => semanticModel.GetSemanticInfo(i).Symbol == bazSymbol);