private void AddAbnormalEdges(ControlFlowGraph graph) { if (graph.SubGraphs.Count == 0) { return; } // Since exception handlers make it possible to transfer control to the handler block // at any time, we have these "abnormal edges" from each node in the try block // to the first node in the handler block (or filter block). // First, add the initial abnormal handler edges from every try-start to the handler-start (or filter start). // This allows us to do some more dominator-magic, where we can just infer the handler body based // on the nodes dominated by the handler node. foreach (var subGraph in graph.SubGraphs.OrderBy(x => x.Nodes.Count)) { var ehFrame = (EHFrame)subGraph.UserData[EHFrame.EHFrameProperty]; // Find the try entry node. var tryEntry = GetNode(graph, (long)ehFrame.TryStart); tryEntry.UserData[ControlFlowGraph.TryStartProperty] = ehFrame; // Find the handler entry node. var handlerEntry = GetNode(graph, (long)ehFrame.HandlerAddress); handlerEntry.UserData[ControlFlowGraph.HandlerStartProperty] = ehFrame; // Add initial abnormal edge. if (ehFrame.Type != EHType.FILTER) { // Jump straight to the handler entry. AddAbnormalEdge(graph, tryEntry, ehFrame, handlerEntry); } else { // Jump to the filter entry. var filterEntry = GetNode(graph, (long)ehFrame.FilterAddress); filterEntry.UserData[ControlFlowGraph.FilterStartProperty] = ehFrame; AddAbnormalEdge(graph, tryEntry, ehFrame, filterEntry); // Connect all terminators of the filter block to the handler entry. foreach (var terminator in FindReachableReturnNodes(filterEntry)) { AddAbnormalEdge(graph, terminator, ehFrame, handlerEntry); } } } // Obtain dominator info. var dominatorInfo = new DominatorInfo(graph.Entrypoint); // Add all handler nodes to the cluster, and add abnormal edges for each try node to the handler start node. var handlerExits = new Dictionary <EHFrame, ICollection <Node> >(); foreach (var subGraph in graph.SubGraphs.OrderBy(x => x.Nodes.Count)) { var ehFrame = (EHFrame)subGraph.UserData[EHFrame.EHFrameProperty]; var tryEntry = GetNode(graph, (long)ehFrame.TryStart); var handlerEntry = GetNode(graph, (long)ehFrame.HandlerAddress); // Determine the handler exits. var handlerBody = CollectHandlerNodes(handlerEntry, dominatorInfo.GetDominatedNodes(handlerEntry)); foreach (var handlerNode in handlerBody) { subGraph.Nodes.Add(handlerNode); } handlerExits.Add(ehFrame, new HashSet <Node>(handlerBody.Where(x => x.OutgoingEdges.Count == 0))); // Add for each node in the try block an abnormal edge. var tryBody = new HashSet <Node>(subGraph.Nodes.Except(handlerBody)); foreach (var node in tryBody.Where(n => !n.UserData.ContainsKey(ControlFlowGraph.TopMostEHProperty) && n != tryEntry)) { AddAbnormalEdge(graph, node, ehFrame, handlerEntry); } // Register EH boundaries in the sub graph. subGraph.UserData[ControlFlowGraph.TryBlockProperty] = tryBody; subGraph.UserData[ControlFlowGraph.HandlerBlockProperty] = handlerBody; if (ehFrame.Type == EHType.FILTER) { var filterEntry = GetNode(graph, (long)ehFrame.FilterAddress); subGraph.UserData[ControlFlowGraph.FilterStartProperty] = filterEntry; } } // Since a LEAVE instruction might not directly transfer control to the referenced instruction, // but rather transfer control to a finally block first, we have to add edges to these nodes // as well. foreach (var node in graph.Nodes) { if (node.SubGraphs.Count > 0) { // Check if the node ends with a LEAVE. var block = GetUserData <ILBasicBlock>(node, ILBasicBlock.BasicBlockProperty); if (block == null) { continue; } var last = block.Instructions[block.Instructions.Count - 1]; if (last.OpCode.Code == ILCode.LEAVE) { // Find the frame we're jumping out of. var ehFrame = last.ProgramState.EHStack.Peek(); // Add for each handler exit an edge to the referenced instruction. foreach (var exit in handlerExits[ehFrame]) { var edge = CreateEdge(exit, node.OutgoingEdges.First().Target, ControlFlowGraph.EndFinallyConditionLabel); exit.UserData[ControlFlowGraph.TopMostEHProperty] = ehFrame; graph.Edges.Add(edge); } } } } }
private void AddFallThroughEdge(ControlFlowGraph graph, Node node, long nextOffset) { node.OutgoingEdges.Add(GetNode(graph, nextOffset)); }