private void ComputeMethodCfg(MethodDefinition method) { var methodName = method.GetCompatibleFullName(); if (Cfg.Procs.ContainsKey(methodName)) { Log.WriteWarning($"Method with duplicate full name found: {methodName }"); return; } var programState = new ProgramState(method, Cfg); var methodBody = method.Body; // True if the translation terminates early, false otherwise. var translationUnfinished = false; if (!method.IsAbstract && methodBody.Instructions.Count > 0) { programState.PushInstruction(methodBody.Instructions.First()); do { var nextInstruction = programState.PopInstruction(); // Checks if there is a node for the offset that we can reuse. (var nodeAtOffset, var excessiveVisits) = programState.GetOffsetNode(nextInstruction.Offset); if (nodeAtOffset != null) { programState.PreviousNode.Successors.Add(nodeAtOffset); } else if (excessiveVisits) { TimeoutMethodCount++; Log.WriteError("Translation timeout."); Log.RecordUnfinishedMethod(programState.Method.GetCompatibleFullName(), nextInstruction.RemainingInstructionCount()); translationUnfinished = true; break; } else if (!InstructionParser.ParseCilInstruction(nextInstruction, programState)) { Log.RecordUnfinishedMethod(programState.Method.GetCompatibleFullName(), nextInstruction.RemainingInstructionCount()); translationUnfinished = true; break; } } while (programState.HasInstruction); } // We add method to cfg only if its translation is finished. Otherwise, we skip that method. if (translationUnfinished && !IsDisposeFunction(method)) { // Deregisters resources of skipped method. programState.ProcDesc.DeregisterResources(Cfg); } else { // Sets exception sink node as default exception node for all nodes in the graph. foreach (var node in programState.ProcDesc.Nodes) { node.ExceptionNodes.Add(programState.ProcDesc.ExceptionSinkNode); } // Exception node for start and exception sink should be exit, exception node for exit // should be empty. programState.ProcDesc.StartNode.ExceptionNodes.Clear(); programState.ProcDesc.ExitNode.ExceptionNodes.Clear(); programState.ProcDesc.ExceptionSinkNode.ExceptionNodes.Clear(); programState.ProcDesc.StartNode.ExceptionNodes.Add(programState.ProcDesc.ExitNode); programState.ProcDesc.ExceptionSinkNode.ExceptionNodes.Add( programState.ProcDesc.ExitNode); SetNodePredecessors(programState); Cfg.Procs.Add(methodName, programState.ProcDesc); } }
private void ComputeMethodCfg(MethodDefinition method) { var methodName = method.GetCompatibleFullName(); if (Cfg.Procs.ContainsKey(methodName)) { Log.WriteWarning($"Method with duplicate full name found: {methodName }"); return; } var programState = new ProgramState(method, Cfg); var methodBody = method.Body; var unhandledExceptionCase = programState.MethodExceptionHandlers.UnhandledExceptionBlock || !programState.MethodExceptionHandlers.NoNestedTryCatchFinally() || !programState.MethodExceptionHandlers.NoFinallyEndWithThrow(); // True if the translation terminates early, false otherwise. var translationUnfinished = false; if (!method.IsAbstract && methodBody.Instructions.Count > 0) { programState.PushInstruction(methodBody.Instructions.First()); do { var nextInstruction = programState.PopInstruction(); // Checks if there is a node for the offset that we can reuse. (var nodeAtOffset, var excessiveVisits) = programState.GetOffsetNode( nextInstruction.Offset, programState.PreviousNode?.BlockEndOffset ?? MethodExceptionHandlers.DefaultHandlerEndOffset); // We don't reuse nodes of finally handlers. if (nodeAtOffset != null && !programState.MethodExceptionHandlers .FinallyOffsetToFinallyHandler .ContainsKey(nextInstruction.Offset) && !programState.MethodExceptionHandlers .CatchOffsetToCatchHandler .ContainsKey(nextInstruction.Offset)) { programState.PreviousNode.Successors.Add(nodeAtOffset); } else if (unhandledExceptionCase) { Log.WriteWarning($"Unhandled exception-handling."); Log.RecordUnknownInstruction("unhandled-exception"); Log.RecordUnfinishedMethod(programState.Method.GetCompatibleFullName(), nextInstruction.RemainingInstructionCount()); translationUnfinished = true; break; } else if (excessiveVisits) { TimeoutMethodCount++; Log.WriteWarning("Translation timeout."); Log.RecordUnfinishedMethod(programState.Method.GetCompatibleFullName(), nextInstruction.RemainingInstructionCount()); translationUnfinished = true; break; } else if (!InstructionParser.ParseCilInstruction(nextInstruction, programState)) { Log.RecordUnfinishedMethod(programState.Method.GetCompatibleFullName(), nextInstruction.RemainingInstructionCount()); translationUnfinished = true; break; } } while (programState.HasInstruction); } // We add method to cfg only if its translation is finished. Otherwise, we skip that // method. if (translationUnfinished && !IsDisposeFunction(method)) { // Deregisters resources of skipped method. programState.ProcDesc.DeregisterResources(Cfg); } else { // Sets exception sink node as default exception node for all nodes in the graph. foreach (var node in programState.ProcDesc.Nodes) { // Nodes linked with exception handlers should not be linked with the sink, and // will already have the corresponding nodes linked. if (node.ExceptionNodes.Count == 0) { node.ExceptionNodes.Add(programState.ProcDesc.ExceptionSinkNode); } } // Exception node for start and exception sink should be exit, exception node for exit // should be empty. programState.ProcDesc.StartNode.ExceptionNodes.Clear(); programState.ProcDesc.ExitNode.ExceptionNodes.Clear(); programState.ProcDesc.ExceptionSinkNode.ExceptionNodes.Clear(); programState.ProcDesc.StartNode.ExceptionNodes.Add(programState.ProcDesc.ExitNode); programState.ProcDesc.ExceptionSinkNode.ExceptionNodes.Add( programState.ProcDesc.ExitNode); SetNodePredecessors(programState); Cfg.Procs.Add(methodName, programState.ProcDesc); } }