使用Mono.Cecil 0.10.2无法获得指令的行号

时间:2019-02-04 19:19:05

标签: c# mono.cecil

我正在尝试通过以下方法获取与Instruction对象关联的行号。应该为SequencePoint.StartLine提供我所需的信息,但是在方法的注释掉部分中seqPoint始终为空。

    /// <summary>
    /// Finds all places in code where one or more methods are called.
    /// </summary>
    /// <param name="classOfMethods">Full name of the class that contains the methods to find.</param>
    /// <param name="methodNames">Names of the methods to find in code.</param>
    public MethodCall[] FindAllMethodCalls(Type classOfMethods, params string[] methodNames)
    {
        #region Use Mono.Cecil to find all instances where methods are called
        var methodCalls = new List<MethodCall>();
        var ad = AssemblyDefinition.ReadAssembly(binaryFileToSearch, new ReaderParameters { ReadSymbols = true });
        foreach (var module in ad.Modules)
        {
            foreach (var type in module.GetTypes())
            {
                foreach (var method in type.Methods.Where(x => x.HasBody))
                {
                    var instrs = method.Body.Instructions.Where(x => x.OpCode == OpCodes.Call).ToArray();
                    foreach (var instr in instrs)
                    {
                        var mRef = instr.Operand as MethodReference;
                        if (mRef != null && mRef.DeclaringType.FullName == classOfMethods.FullName && methodNames.Contains(mRef.Name))
                        {
                            // this does not work -- always returns null
                            //var seqPoint = method.DebugInformation.GetSequencePoint(instr);
                            //if (seqPoint != null)
                            //{
                            //}

                            methodCalls.Add(new MethodCall
                            {
                                CodeFile = method.DebugInformation.SequencePoints.First().Document.Url,
                                MethodRef = mRef,
                            });
                        }
                    }
                }
            }
        }
        ...
        return methodCalls.ToArray();
    }

我在其上调用AssemblyDefinition.ReadAssembly()的二进制文件具有相应的.pdb文件,并且我正在使用ReadSymbols = true选项。我在做什么错了?

1 个答案:

答案 0 :(得分:0)

您的代码确定。

Cecil应该在何时读取PDB文件。在读取过程中,他将填充所有PDB函数:(这不是完整的真实代码,但用于演示,尽管实际代码相似

private bool PopulateFunctions()
{
    PdbFunction[] array = PdbFile.LoadFunctions(.....);

    foreach (PdbFunction pdbFunction in array)
    {
        this.functions.Add(pdbFunction.token, pdbFunction);
    }
}

然后,当他阅读MethodBody时,他会填充序列点:

private void ReadSequencePoints(PdbFunction function, MethodDebugInformation info)
{
    foreach (PdbLines lines in function.lines)
    {
        this.ReadLines(lines, info);
    }
}

然后

private static void ReadLine(PdbLine line, Document document, MethodDebugInformation info)
    {
        SequencePoint sequencePoint = new SequencePoint(ine.offset, document);
        sequencePoint.StartLine = line.lineBegin;
        sequencePoint.StartColumn = line.colBegin;
        sequencePoint.EndLine = line.lineEnd;
        sequencePoint.EndColumn = line.colEnd;
        info.sequence_points.Add(sequencePoint);
    }

如果找不到特定的序列点,则意味着它不存在于方法调试信息的序列点集合中。

无论如何,我怀疑您是否总是空。

请写下:

 method.DebugInformation.GetSequencePointMapping()

并将其与您的instrs收藏集进行比较。

method.DebugInformation.GetSequencePointMapping()是Cecil知道的序列点,对于每个序列点,您都可以看到它映射到的指令,因此您可以检查方法中的哪个调用指令具有序列点。 / p>