Пример #1
0
        private void BuildIndexes(List <ModuleDefMD> modules)
        {
            foreach (var module in modules)
            {
                foreach (var typeDef in module.GetTypes())
                {
                    stat.TypeCount++;
                    if (!typeDef.HasMethods)
                    {
                        continue;
                    }

                    foreach (var methodDef in typeDef.Methods)
                    {
                        stat.MethodCount++;
                        if (!methodDef.HasBody)
                        {
                            continue;
                        }
                        if (!methodDef.Body.HasInstructions)
                        {
                            continue;
                        }

                        CallInfo cacheInfo = null;
                        foreach (var instruction in methodDef.Body.Instructions)
                        {
                            // TODO: check opcode
                            //    call: 802655
                            //    callvirt: 918700
                            //    newobj: 255686
                            //    ldsfld: 27607
                            //    ldfld: 57948
                            //    stfld: 23493
                            //    ldftn: 41261
                            //    ldflda: 4556
                            //    ldvirtftn: 1453
                            //    stsfld: 2023
                            //    ldtoken: 622
                            //    ldsflda: 24
                            if (instruction.Operand is IMethod methodOperand)
                            {
                                CallInfo newInfo;
                                if (cacheInfo == null)
                                {
                                    newInfo = new CallInfo(
                                        new AssemblyInfo(module.Assembly.Name, module.Assembly.Version),
                                        methodDef.CreateMethodUniqueName(),
                                        instruction.OpCode,
                                        methodDef.IsPublicGlobalVisibility(),
                                        methodDef.FindOverrides().Select(md => md.CreateMethodUniqueName()).ToList());
                                    cacheInfo = newInfo;
                                }
                                else
                                {
                                    newInfo = new CallInfo(
                                        cacheInfo.AssemblyInfo,
                                        cacheInfo.Signature,
                                        instruction.OpCode,
                                        cacheInfo.IsPublic,
                                        cacheInfo.OverrideSignatures);
                                }

                                // TODO PERF add cache for AssemblyInfo
                                var assemblyInfo = new AssemblyInfo(
                                    methodOperand.DeclaringType.DefinitionAssembly.Name,
                                    methodOperand.DeclaringType.DefinitionAssembly.Version);
                                var key = methodOperand.CreateMethodUniqueName();
                                if (callers.TryGetValue(key, out var callInfoMap))
                                {
                                    if (callInfoMap.TryGetValue(assemblyInfo, out var list))
                                    {
                                        list.Add(newInfo);
                                    }
                                    else
                                    {
                                        callInfoMap.Add(assemblyInfo, new List <CallInfo>()
                                        {
                                            newInfo
                                        });
                                    }
                                }
                                else
                                {
                                    callers.Add(key, new Dictionary <AssemblyInfo, List <CallInfo> >()
                                    {
                                        { assemblyInfo, new List <CallInfo>()
                                          {
                                              newInfo
                                          } }
                                    });
                                }
                            }
                        }
                    }
                }
            }
        }
Пример #2
0
        private CallGraph CreateGraphInternal(List <PatternInfo> patterns)
        {
            var graph = new CallGraph();
            var processingEntities = new Queue <ProcessingEntity>();

            foreach (var pattern in patterns)
            {
                var calls = index.GetCalls(pattern);
                if (calls.Count > 0)
                {
                    // HACK if we found call w/ version restriction
                    // then we add it and find again w/o version restrictions
                    // in practice the result should be the same (but not always)
                    var info = new CallInfo(
                        new AssemblyInfo(UTF8String.Empty, pattern.RequiredOlderVersion),
                        pattern.Method,
                        OpCodes.Call,
                        true,
                        new List <MethodUniqueSignature>(0));
                    var node = new CallGraphNode(info);
                    graph.Nodes.Add(pattern.Method, node);
                    processingEntities.Enqueue(new ProcessingEntity(node.MethodSignature, node));
                }
            }

            while (processingEntities.Count > 0)
            {
                var entity = processingEntities.Dequeue();

                var calls = index.GetCalls(entity.Signature /*, entity.Node.AssemblyInfo*/);
                if (calls.Count != 0)
                {
                    foreach (var callInfo in calls)
                    {
                        if (callInfo.Opcode.Code != Code.Call &&
                            callInfo.Opcode.Code != Code.Callvirt &&
                            callInfo.Opcode.Code != Code.Newobj &&
                            callInfo.Opcode.Code != Code.Ldtoken)          // used into Expression Tree in KB, need to implement DFA
                        //resume.Opcode.Code != Code.Ldvirtftn &&    // can use with calli
                        //resume.Opcode.Code != Code.Ldftn)          // https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.calli?view=netframework-4.7.2
                        {
                            // just ignore it for now, need to implement DFA
                            stat.IgnoredOpcodes.Add(callInfo.Opcode.Code);
                            continue;
                        }

                        if (graph.Nodes.TryGetValue(callInfo.Signature, out var callingNode))
                        {
                            // TODO: need to add a new kind of cycled edge to remove recursive calls in RemoveNonPublicEntryNodes
                            //callingNode.OutNodes.Add(entity.Node);
                            //entity.Node.InNodes.Add(callingNode);
                        }
                        else
                        {
                            callingNode = new CallGraphNode(callInfo);
                            callingNode.OutNodes.Add(entity.Node);
                            entity.Node.InNodes.Add(callingNode);

                            graph.Nodes.Add(callInfo.Signature, callingNode);
                            processingEntities.Enqueue(new ProcessingEntity(callInfo.Signature, callingNode));

                            foreach (var overrideSignature in callInfo.OverrideSignatures)
                            {
                                processingEntities.Enqueue(new ProcessingEntity(overrideSignature, callingNode));
                            }
                        }
                    }
                }
            }

            foreach (var node in graph.Nodes.Values)
            {
                if (node.InNodes.Count != 0)
                {
                    continue;
                }

                graph.EntryNodes.Add(node.MethodSignature, node);
            }

            return(graph);
        }