/// <summary> /// Splits the BasicBlock in <paramref name="functionUnit"/> that contains a user-defined /// label with the name <paramref name="name"/>, and returns the new BasicBlock as a /// result of the split. /// </summary> /// /// <param name="functionUnit">Function unit that contains the label.</param> /// <param name="name">Name of the user-defined label to find.</param> /// <returns>New BasicBlock in <paramref name="functionUnit"/> /// that results from a split at the user-defined label with the name /// <paramref name="name"/>; null otherwise.</returns> /// <remarks>Precondition: There is only one user-defined label with /// the name <paramref name="name"/>.</remarks> public static Phx.Graphs.BasicBlock SplitAtUserLabel(Phx.FunctionUnit functionUnit, string name) { Phx.Graphs.FlowGraph flowGraph = functionUnit.FlowGraph; Phx.Graphs.BasicBlock result = null; foreach (Phx.IR.Instruction instruction in functionUnit.Instructions) { if (instruction.Opcode == Phx.Common.Opcode.UserLabel) { Phx.IR.Operand userLabelOperand = instruction.SourceOperand; string operandName = userLabelOperand.ToString(); /* Fix the label name, if needed. */ if (operandName.StartsWith("$")) { operandName = operandName.Substring(1); } if (operandName == name) { Phx.Graphs.BasicBlock block = instruction.BasicBlock; result = flowGraph.SplitBlock(block, instruction); break; } } } if (result == null) { Console.Out.WriteLine("PHOENIX: Cannot find user-defined label: " + name); Console.Out.WriteLine("Exiting GameTime."); Environment.Exit(1); } return(result); }
/// <summary> /// Inject code coverage information into a function. /// </summary> /// <param name="unit">The function to instrument.</param> protected override void Execute(Phx.Unit unit) { // Only instrument MSIL functions if (!unit.IsFunctionUnit) { return; } Phx.FunctionUnit function = unit.AsFunctionUnit; if (!function.Architecture.NameString.Equals("Msil")) { return; } Phx.PEModuleUnit module = function.ParentUnit.AsPEModuleUnit; Phx.Symbols.FunctionSymbol functionSymbol = function.FunctionSymbol; Phx.Types.FunctionType functionType = functionSymbol.FunctionType; // Create the method signature List <string> parameterTypes = new List <string>(); foreach (Phx.Types.Parameter parameter in functionType.UserDefinedParameters) { parameterTypes.Add(parameter.Type.ToString()); } string methodName = string.Format( CultureInfo.InvariantCulture, "{0}({1})", functionSymbol.NameString, string.Join(", ", parameterTypes.ToArray())); // Build the control flow graph for the current function function.BuildFlowGraph(); Phx.Graphs.FlowGraph flow = function.FlowGraph; // Log method details string typeName = (functionSymbol.EnclosingAggregateType != null) ? functionSymbol.EnclosingAggregateType.TypeSymbol.NameString : "<Module>"; Log.StartMethod( methodName, typeName, flow.StartBlock.FirstInstruction.GetFileName(), flow.StartBlock.FirstInstruction.GetLineNumber()); // Create a mapping of the disassembled from instructions to the // basic block IDs so we can use them for coverage viewing. Dictionary <Phx.IR.Instruction, uint> dissassembly = new Dictionary <Phx.IR.Instruction, uint>(); // Instrument and log the blocks for the current function. Log.StartBlocks(); foreach (Phx.Graphs.BasicBlock block in flow.BasicBlocks) { // Find the first real instruction in the block Phx.IR.Instruction first = null; foreach (Phx.IR.Instruction instruction in block.Instructions) { // Save the instructions to be dumped later dissassembly.Add(instruction, BlockCounter); // Ignore instructions that aren't actually "real" if (first == null && instruction.IsReal) { Phx.Common.Opcode opcode = instruction.Opcode as Phx.Common.Opcode; if (opcode == Phx.Common.Opcode.ReturnFinally || opcode == Phx.Common.Opcode.Leave || opcode == Phx.Common.Opcode.Unreached || opcode == Phx.Common.Opcode.ExitTypeFilter) { continue; } first = instruction; } } // Inject a code coverage visitor call before the first // instruction of the basic block if (first != null) { // Log the basic block Phx.IR.Instruction last = block.LastInstruction; Log.StartBlock( BlockCounter, first.GetMsilOffset(), first.GetFileName(), first.GetLineNumber(), first.GetColumnNumber(), last.GetLineNumberEnd(), last.GetColumnNumberEnd()); Phx.Symbols.FunctionSymbol coverageVisit = GetFunctionSymbol(module, CoverageVisitAssembly, CoverageVisitType, CoverageVisitMethod); InjectCoverageCall(function, coverageVisit, BlockCounter, first); #if LogBlockDissassembly // Dump the disassembly for the current block Log.StartBlockDisassembly(); foreach (Phx.IR.Instruction instruction in block.Instructions) { Log.WriteBlockDisassembly( instruction.GetMsilOffset(), instruction.ToString(), BlockCounter); } Log.EndBlockDisassembly(); #endif Log.EndBlock(); } // Increment the number of basic blocks BlockCounter++; } function.DeleteFlowGraph(); Log.EndBlocks(); // Dump the disassembly for the current method Log.StartMethodDisassembly(); foreach (KeyValuePair <Phx.IR.Instruction, uint> pair in dissassembly) { Log.WriteBlockDisassembly( pair.Key.GetMsilOffset(), pair.Key.ToString(), pair.Value); } Log.EndMethodDisassembly(); Log.EndMethod(); }
/// <summary> /// Dumps the DOT representation of the control-flow graph of the input function unit /// in a file (a DAG file labeled with the name of the function unit) that will be /// further processed by the GameTime Python scripts. /// </summary> /// /// <param name="functionUnit">Phoenix function unit whose control-flow graph is /// to be dumped.</param> /// <param name="sourceNodeId">ID of the BasicBlock in the control-flow /// graph to start the analysis from.</param> /// <param name="sinkNodeId">ID of the BasicBlock in the control-flow /// graph to end the analysis at.</param> /// <param name="config">Configuration object that contains /// GameTime configuration information.</param> /// <param name="projectConfig">ProjectConfiguration object that contains /// project configuration information.</param> public static void DumpCfgToFile(Phx.FunctionUnit functionUnit, uint sourceNodeId, uint sinkNodeId, Utilities.Configuration config, ProjectConfiguration projectConfig) { Console.Out.WriteLine("PHOENIX: Dumping a DOT representation of the " + "control-flow graph..."); string funcName = GetFunctionName(functionUnit); Phx.Graphs.FlowGraph flowGraph = functionUnit.FlowGraph; Phx.Lifetime lifetime = functionUnit.Lifetime; if (projectConfig.debugConfig.DUMP_IR) { Console.Out.WriteLine("PHOENIX: Dumping IR..."); string irFileName = System.IO.Path.Combine(projectConfig.locationTempDir, config.TEMP_PHX_IR); StreamWriter irWriter = new StreamWriter(irFileName, true); irWriter.AutoFlush = true; foreach (Phx.Graphs.BasicBlock block in flowGraph.BasicBlocks) { irWriter.WriteLine("*** BASIC BLOCK " + block.Id + " ***"); foreach (Phx.IR.Instruction instruction in block.Instructions) { irWriter.WriteLine(instruction); } } irWriter.Close(); } /* Perform a reachability analysis from the source node: determine * what nodes and edges can be reached from the source node. */ Phx.BitVector.Sparse blocksVisitedFromSource = Phx.BitVector.Sparse.New(lifetime); Phx.BitVector.Sparse blocksToVisitFromSource = Phx.BitVector.Sparse.New(lifetime); Phx.BitVector.Sparse edgesVisitedFromSource = Phx.BitVector.Sparse.New(lifetime); blocksToVisitFromSource.SetBit(sourceNodeId); /* TODO: Make more efficient. */ while (!blocksToVisitFromSource.IsEmpty) { uint blockToVisitId = blocksToVisitFromSource.RemoveFirstBit(); blocksVisitedFromSource.SetBit(blockToVisitId); Phx.Graphs.BasicBlock blockToVisit = flowGraph.Node(blockToVisitId) as Phx.Graphs.BasicBlock; foreach (Phx.Graphs.FlowEdge edge in blockToVisit.SuccessorEdges) { Phx.Graphs.BasicBlock successor = edge.SuccessorNode; uint succId = successor.Id; uint edgeId = edge.Id; if (!blocksVisitedFromSource.GetBit(succId)) { blocksToVisitFromSource.SetBit(succId); edgesVisitedFromSource.SetBit(edgeId); } } } /* Perform a backward reachability analysis from the sink node: determine * what nodes and edges can be reached from the sink node. */ Phx.BitVector.Sparse blocksVisitedFromSink = Phx.BitVector.Sparse.New(lifetime); Phx.BitVector.Sparse blocksToVisitFromSink = Phx.BitVector.Sparse.New(lifetime); Phx.BitVector.Sparse edgesVisitedFromSink = Phx.BitVector.Sparse.New(lifetime); blocksToVisitFromSink.SetBit(sinkNodeId); while (!blocksToVisitFromSink.IsEmpty) { uint blockToVisitId = blocksToVisitFromSink.RemoveFirstBit(); blocksVisitedFromSink.SetBit(blockToVisitId); Phx.Graphs.BasicBlock blockToVisit = flowGraph.Node(blockToVisitId) as Phx.Graphs.BasicBlock; foreach (Phx.Graphs.FlowEdge edge in blockToVisit.PredecessorEdges) { Phx.Graphs.BasicBlock predecessor = edge.PredecessorNode; uint predId = predecessor.Id; uint edgeId = edge.Id; if (!blocksVisitedFromSink.GetBit(predId)) { blocksToVisitFromSink.SetBit(predId); edgesVisitedFromSink.SetBit(edgeId); } } } /* Determine which blocks and edges in the control-flow graph can be reached from * *both* the source and the sink: this is the section of the control-flow graph * that we are interested in. */ blocksVisitedFromSource.And(blocksVisitedFromSink); edgesVisitedFromSource.And(edgesVisitedFromSink); uint numNodes = (uint)blocksVisitedFromSource.GetBitCount(); uint numEdges = (uint)edgesVisitedFromSource.GetBitCount(); uint numNewNodes = numNodes + numNodes; uint numNewEdges = numEdges + numNodes + 1; /* Mapping between old block IDs and new block IDs. */ Dictionary <uint, uint> idMap = new Dictionary <uint, uint>(); /* Create a writer to write the DAG in DOT format to a file. */ string dagFileName = System.IO.Path.Combine(projectConfig.locationTempDir, config.TEMP_DAG); StreamWriter dagWriter = new StreamWriter(dagFileName); dagWriter.AutoFlush = true; /* Qualify the DAG. */ dagWriter.WriteLine("digraph " + funcName + " {"); uint newMappedBlockId = 1; uint newFakeBlockId = numNodes + 1; foreach (Phx.Graphs.BasicBlock basicBlock in flowGraph.BasicBlocks) { uint blockId = basicBlock.Id; /* Is the block in the portion of the control-flow graph * we are concerned about? */ if (blocksVisitedFromSource.GetBit(blockId)) { uint mappedBlockId; if (idMap.ContainsKey(blockId)) { mappedBlockId = idMap[blockId]; } else { idMap.Add(blockId, newMappedBlockId); mappedBlockId = newMappedBlockId++; } /* Keep track of the edges that may be added to the resulting DAG. */ List <Pair <uint, uint> > edges = new List <Pair <uint, uint> >(); /* First edge that may be added to the DAG: it will be added * if there are successors. */ edges.Add(new Pair <uint, uint>(mappedBlockId, newFakeBlockId)); List <Phx.Graphs.FlowEdge> reverseSuccessorList = new List <Phx.Graphs.FlowEdge>(); foreach (Phx.Graphs.FlowEdge edge in basicBlock.SuccessorEdges) { reverseSuccessorList.Add(edge); } reverseSuccessorList.Reverse(); foreach (Phx.Graphs.FlowEdge edge in reverseSuccessorList) { /* Is the block in the portion of the control-flow graph * we are concerned about? */ Phx.Graphs.BasicBlock successor = edge.SuccessorNode; uint succId = successor.Id; if (blocksVisitedFromSource.GetBit(succId)) { uint mappedSuccId; if (idMap.ContainsKey(succId)) { mappedSuccId = idMap[succId]; } else { idMap.Add(succId, newMappedBlockId); mappedSuccId = newMappedBlockId++; } /* Replace each BasicBlock with two edges, * separated by a new, "fake" node. */ edges.Add(new Pair <uint, uint>(newFakeBlockId, mappedSuccId)); } } if (edges.Count > 1) { /* This node has successors in the "snipped" CFG. */ foreach (Pair <uint, uint> edge in edges) { dagWriter.WriteLine(" " + edge.First + " -> " + edge.Second + ";"); } /* Generate the ID of a "fake" node corresponding to * the next node, if any. */ newFakeBlockId++; } } } /* Add a "dummy" edge from the sink. */ dagWriter.WriteLine(" " + idMap[sinkNodeId] + " -> " + numNewNodes + ";"); dagWriter.WriteLine("}"); dagWriter.Close(); /* Copy the mappings to a file. */ string blockIdMapFile = System.IO.Path.Combine(projectConfig.locationTempDir, config.TEMP_DAG_ID_MAP); StreamWriter blockIdMapWriter = new StreamWriter(blockIdMapFile); blockIdMapWriter.AutoFlush = true; foreach (uint key in idMap.Keys) { uint blockVisitedId = key; uint newBlockId = idMap[key]; blockIdMapWriter.WriteLine(newBlockId + " " + blockVisitedId); } blockIdMapWriter.Close(); }
/// <summary> /// Finds the conditions along a path. /// </summary> /// /// <param name="functionUnit">Phoenix function unit.</param> /// <param name="config">Configuration object that contains GameTime /// configuration information.</param> /// <param name="projectConfig">ProjectConfiguration object that /// contains project configuration information.</param> public static void FindPathConditions(Phx.FunctionUnit functionUnit, Utilities.Configuration config, ProjectConfiguration projectConfig) { Console.Out.WriteLine("PHOENIX: Finding the conditions and " + "assignments along a path..."); Console.Out.WriteLine("PHOENIX: Reading in the DAG..."); /* Read in the DAG and deduce associated information. The DAG is in DOT file format. */ string dagFileName = System.IO.Path.Combine(projectConfig.locationTempDir, config.TEMP_DAG); TextReader dagReader = new StreamReader(dagFileName); /* Ignore the first line. */ dagReader.ReadLine(); /* Read in the nodes and the edges of the graph. */ HashSet <string> dagNodes = new HashSet <string>(); HashSet <Pair <string, string> > dagEdges = new HashSet <Pair <string, string> >(); string dagEdge = null; while ((dagEdge = dagReader.ReadLine()) != null) { dagEdge = dagEdge.Replace("{", ""); dagEdge = dagEdge.Replace("}", ""); dagEdge.Trim(); if (dagEdge.Length != 0) { /* Ignore the semicolon. */ dagEdge = dagEdge.Trim(';'); /* Split at the arrow. */ dagEdge = dagEdge.Replace("->", ">"); string[] edgeNodes = dagEdge.Split('>'); /* Find the nodes incident to the edge. */ edgeNodes[0] = edgeNodes[0].Trim(); edgeNodes[1] = edgeNodes[1].Trim(); /* Add the nodes and the edge. */ dagNodes.Add(edgeNodes[0]); dagNodes.Add(edgeNodes[1]); dagEdges.Add(new Pair <string, string>(edgeNodes[0], edgeNodes[1])); } } dagReader.Close(); uint numNodes = (uint)dagNodes.Count; uint numEdges = (uint)dagEdges.Count; Console.Out.WriteLine("PHOENIX: DAG has " + numNodes + " nodes and " + numEdges + " edges."); Console.Out.WriteLine("PHOENIX: There are at most " + (numEdges - numNodes + 2) + " basis paths."); /* How many nodes are there in the original DAG, without the fake * intermediate nodes? */ uint actualNumNodes = (numNodes / 2); uint actualNumEdges = (numEdges - actualNumNodes - 1); /* Get the successors of the nodes that existed in the * original DAG (without the fake intermediate nodes). */ Dictionary <uint, uint> nodeSuccessors = new Dictionary <uint, uint>(); foreach (Pair <string, string> edge in dagEdges) { uint sourceNodeId = Convert.ToUInt32(edge.First); uint sinkNodeId = Convert.ToUInt32(edge.Second); /* Yes, there can be more than one successor for any given node. * However, we are guaranteed that for the nodes in the original * DAG, there is exactly one (fake) successor node. We are only * concerned about these nodes. There is no great way to programatically * determine these successor nodes. */ if (sourceNodeId <= actualNumNodes) { nodeSuccessors.Add(sourceNodeId, sinkNodeId); } } Console.Out.WriteLine("PHOENIX: Finished reading and processing the DAG."); Console.Out.WriteLine("PHOENIX: Reading the block ID map..."); /* Read and store the mapping between "adjusted" block IDs and "actual" * block IDs. Also, store the reverse mapping for quick conversion * in the other direction. */ Dictionary <uint, uint> adjustedToActual = new Dictionary <uint, uint>(); Dictionary <uint, uint> actualToAdjusted = new Dictionary <uint, uint>(); string idMapFileName = System.IO.Path.Combine(projectConfig.locationTempDir, config.TEMP_DAG_ID_MAP); string[] idMappings = File.ReadAllLines(idMapFileName); foreach (string idMapping in idMappings) { string[] idMappingArray = idMapping.Split(' '); uint adjustedBlockId = Convert.ToUInt32(idMappingArray[0]); uint actualBlockId = Convert.ToUInt32(idMappingArray[1]); adjustedToActual.Add(adjustedBlockId, actualBlockId); actualToAdjusted.Add(actualBlockId, adjustedBlockId); } Console.Out.WriteLine("PHOENIX: Finished reading and processing the ID map."); Console.Out.WriteLine(); Console.Out.WriteLine("PHOENIX: Reading in the candidate path..."); /* Read in the candidate path. */ string pathNodesFileName = System.IO.Path.Combine(projectConfig.locationTempDir, config.TEMP_PATH_NODES); TextReader pathNodesReader = new StreamReader(pathNodesFileName); string[] pathNodesArray = pathNodesReader.ReadLine().Split(' '); pathNodesReader.Close(); List <uint> pathNodes = new List <uint>(); foreach (string pathNode in pathNodesArray) { if (pathNode != "") { pathNodes.Add(Convert.ToUInt32(pathNode)); } } /* Convert the adjusted block IDs in the candidate path to the actual block IDs. */ Phx.Graphs.FlowGraph flowGraph = functionUnit.FlowGraph; List <Phx.Graphs.BasicBlock> pathBlocks = new List <Phx.Graphs.BasicBlock>(); int position = 0; while (position < pathNodes.Count) { uint adjustedBlockId = pathNodes[position]; uint actualBlockId = adjustedToActual[adjustedBlockId]; Phx.Graphs.BasicBlock actualBlock = flowGraph.Node(actualBlockId) as Phx.Graphs.BasicBlock; pathBlocks.Add(actualBlock); /* Skip over the "fake" intermediate nodes. */ position = position + 2; } Path path = new Path(pathBlocks, config, projectConfig); Console.Out.WriteLine("PHOENIX: Finished reading and processing the candidate path."); /* Generate the conditions and the assignments along the path. */ Console.Out.WriteLine("PHOENIX: Generating the conditions and " + "assignments along the path..."); Console.Out.WriteLine(); path.GenerateConditionsAndAssignments(); Console.Out.WriteLine("PHOENIX: Finished generating the conditions and assignments."); if (path.ProjectConfig.debugConfig.DUMP_PATH) { path.Dump(); Console.Out.WriteLine(); } List <Pair <Expression, uint> > conditions = path.Conditions; HashSet <Expression> arrayVariables = path.ArrayVariables; Dictionary <Expression, List <uint> > arrayDimensions = path.ArrayDimensions; Console.Out.WriteLine("PHOENIX: Writing information about the path " + "to temporary files..."); Console.Out.WriteLine("PHOENIX: Writing the conditions and assignments..."); string pathConditionsFileName = System.IO.Path.Combine(projectConfig.locationTempDir, config.TEMP_PATH_CONDITIONS); StreamWriter pathConditionsWriter = new StreamWriter(pathConditionsFileName, false); pathConditionsWriter.AutoFlush = true; List <Expression> conditionExprs = new List <Expression>(); foreach (Pair <Expression, uint> conditionPair in conditions) { Expression condition = conditionPair.First; pathConditionsWriter.WriteLine(condition); conditionExprs.Add(condition); } pathConditionsWriter.Close(); Console.Out.WriteLine("PHOENIX: Writing completed."); Console.Out.WriteLine("PHOENIX: Writing line numbers..."); path.DumpLineNumbers(); Console.Out.WriteLine("PHOENIX: Writing completed."); Console.Out.WriteLine("PHOENIX: Writing the edges that correspond to " + "conditions and assignments..."); /* The actual source node that corresponds to a constraint (condition * or assignment) is the dummy node after the adjusted source node. */ path.DumpConditionEdges(sourceNodeId => nodeSuccessors[actualToAdjusted[sourceNodeId]], sinkNodeId => actualToAdjusted[sinkNodeId]); Console.Out.WriteLine("PHOENIX: Writing completed."); Console.Out.WriteLine("PHOENIX: Writing the line numbers and truth values of " + "the conditional points.."); path.DumpConditionTruths(); Console.Out.WriteLine("PHOENIX: Writing completed."); Console.Out.WriteLine("PHOENIX: Writing information about array and " + "aggregate accesses..."); path.DumpAccesses(); Console.Out.WriteLine("PHOENIX: Writing completed."); if (path.ProjectConfig.debugConfig.DUMP_ALL_PATHS) { string allPathsFileName = System.IO.Path.Combine(projectConfig.locationTempDir, config.TEMP_PATH_ALL); StreamWriter allPathsWriter = new StreamWriter(allPathsFileName, true); allPathsWriter.AutoFlush = true; allPathsWriter.Write("*** CANDIDATE PATH ***"); allPathsWriter.WriteLine(path.ToString()); allPathsWriter.Close(); } Console.Out.WriteLine("PHOENIX: Path information written to temporary files."); Console.Out.WriteLine("PHOENIX: Writing the corresponding SMT query to " + "a temporary file..."); string smtQueryFileName = System.IO.Path.Combine(projectConfig.locationTempDir, config.TEMP_PATH_QUERY + ".smt"); StreamWriter smtQueryWriter = new StreamWriter(smtQueryFileName, false); smtQueryWriter.AutoFlush = true; smtQueryWriter.Write(SmtHelper.ConvertToSmtLib2Query(path)); smtQueryWriter.Close(); Console.Out.WriteLine("PHOENIX: Writing completed."); }
/// <summary> /// Private helper workhorse function for <see cref="Execute"/>. /// </summary> /// /// <param name="moduleUnit">The moduleUnit to process.</param> /// <returns>True if successful; false otherwise.</returns> private bool ExecuteHelper(Phx.ModuleUnit moduleUnit) { Console.Out.WriteLine(); Phx.Graphs.CallGraph callGraph = moduleUnit.CallGraph; if (callGraph == null) { Console.Out.WriteLine("PHOENIX: Call graph is null."); Console.Out.WriteLine("Exiting GameTime."); Environment.Exit(1); return(false); } /* Load GameTime configuration. */ string configFile = Console.ReadLine(); Console.Out.WriteLine("PHOENIX: Configuring this GameTime session with " + configFile + "..."); Utilities.Configuration config = Utilities.Configuration.ReadConfigFile(configFile); Console.Out.WriteLine("PHOENIX: Successfully configured this session."); /* Load the project configuration. */ string projectConfigFile = Console.ReadLine(); Console.Out.WriteLine("PHOENIX: Loading project configuration from " + projectConfigFile + "..."); ProjectConfiguration projectConfig = ProjectConfiguration.ReadProjectConfigFile(projectConfigFile, config); Console.Out.WriteLine("PHOENIX: Successfully loaded the project for this session."); /* Determine the current GameTime operation mode. */ string currentMode = Console.ReadLine(); mode = (currentMode.Equals(config.TEMP_PHX_CREATE_DAG)) ? MODES.CREATE_DAG : MODES.FIND_CONDITIONS; Console.Out.WriteLine("PHOENIX: GameTime operation mode is: " + ((mode == MODES.CREATE_DAG) ? "Create DAG." : "Find path conditions.")); /* Find the function to analyze. */ string funcToProcess = projectConfig.func; Console.Out.WriteLine("PHOENIX: Preprocessing " + funcToProcess + "..."); Console.Out.WriteLine(); Console.Out.WriteLine("PHOENIX: Finding the corresponding function unit..."); /* Find the function unit corresponding to the function to be analyzed. */ FunctionUnit functionUnitToProcess = null; /* Traverse the graph in post-order (top-down order). */ Phx.Graphs.NodeFlowOrder nodeOrder = Phx.Graphs.NodeFlowOrder.New(callGraph.Lifetime); nodeOrder.Build(callGraph, Phx.Graphs.Order.PostOrder); Phx.Targets.Runtimes.Runtime runtime = moduleUnit.Runtime; uint functionCount = 0; for (uint i = 1; i <= nodeOrder.NodeCount; ++i) { Phx.Graphs.CallNode node = nodeOrder.Node(i).AsCallNode; if ((node == callGraph.UnknownCallerNode) || (node == callGraph.UnknownCalleeNode)) { continue; } if (node.FunctionSymbol != null) { /* Is this LTCG mode? */ bool isLTCG = false; try { IDictionary env = Environment.GetEnvironmentVariables(); if (env.Contains("LINK_TIME_CODE_GENERATION")) { isLTCG = true; } } catch (ArgumentNullException) { } /* Only perform the check when the LTCG mode is off. */ if (isLTCG || moduleUnit.IsPEModuleUnit) { moduleUnit = node.FunctionSymbol.CompilationUnitParentSymbol.Unit.AsModuleUnit; } /* Create the corresponding function unit. */ Phx.Lifetime lifetime = Phx.Lifetime.New(Phx.LifetimeKind.Function, null); Phx.FunctionUnit functionUnit = Phx.FunctionUnit.New(lifetime, node.FunctionSymbol, Phx.CodeGenerationMode.Native, moduleUnit.TypeTable, runtime.Architecture, runtime, moduleUnit, functionCount++); /* Attach debugging info. */ Phx.Debug.Info.New(functionUnit.Lifetime, functionUnit); node.FunctionSymbol.FunctionUnit = functionUnit; this.PhaseConfiguration.PhaseList.DoPhaseList(functionUnit); functionUnit.Context.PopUnit(); string funcName = FunctionUnitHelper.GetFunctionName(functionUnit); if (funcName == funcToProcess) { functionUnitToProcess = functionUnit; break; } } } if (functionUnitToProcess == null) { Console.Out.WriteLine("PHOENIX: Cannot find function named " + funcToProcess + "."); Console.Out.WriteLine("PHOENIX: Exiting GameTime..."); Environment.Exit(1); return(false); } else { Console.Out.WriteLine("PHOENIX: Function unit found."); } Console.Out.WriteLine("PHOENIX: Preprocessing the function unit..."); FunctionUnitHelper.Preprocess(functionUnitToProcess); Console.Out.WriteLine("PHOENIX: Function unit preprocessing complete."); Console.Out.WriteLine(); Console.Out.WriteLine("PHOENIX: Building the flow graph..."); functionUnitToProcess.BuildFlowGraphWithoutEH(); Phx.Graphs.FlowGraph graph = functionUnitToProcess.FlowGraph; Console.Out.WriteLine("PHOENIX: Flow graph built."); Console.Out.WriteLine("PHOENIX: Snipping the relevant portion of the flow graph..."); uint sourceBlockId = 1; uint sinkBlockId = graph.NodeCount; if (projectConfig.startLabel != "") { Phx.Graphs.BasicBlock sourceBlock = FunctionUnitHelper.SplitAtUserLabel(functionUnitToProcess, projectConfig.startLabel); sourceBlockId = sourceBlock.Id; } if (projectConfig.endLabel != "") { Phx.Graphs.BasicBlock sinkBlock = FunctionUnitHelper.SplitAtUserLabel(functionUnitToProcess, projectConfig.endLabel); /* Correct the sink block: we want the block just before the block * we receive from SplitAtUserLabel. */ Phx.Graphs.FlowEdge edgeToSink = sinkBlock.PredecessorEdgeList; sinkBlock = edgeToSink.PredecessorNode; sinkBlockId = sinkBlock.Id; } Console.Out.WriteLine("PHOENIX: Relevant portion snipped."); Console.Out.WriteLine(); Console.Out.WriteLine("PHOENIX: Starting analysis..."); switch (mode) { case MODES.CREATE_DAG: FunctionUnitHelper.DumpCfgToFile(functionUnitToProcess, sourceBlockId, sinkBlockId, config, projectConfig); break; case MODES.FIND_CONDITIONS: FunctionUnitHelper.FindPathConditions(functionUnitToProcess, config, projectConfig); break; } Console.Out.WriteLine("PHOENIX: Analysis successful."); Console.Out.WriteLine(); Environment.Exit(0); return(true); }