public string FormatControlFlowGraph(ControlFlowGraph cfg) { StringWriter writer = new StringWriter(); foreach (InstructionBlock block in cfg.Blocks) { writer.WriteLine("block {0}:", block.Index); writer.WriteLine("\tbody:"); foreach (Instruction instruction in block) { writer.Write("\t\t"); InstructionData data = cfg.GetData(instruction); writer.Write("[{0}:{1}] ", data.StackBefore, data.StackAfter); Formatter.WriteInstruction(writer, instruction); writer.WriteLine(); } InstructionBlock[] successors = block.Successors; if (successors.Length > 0) { writer.WriteLine("\tsuccessors:"); foreach (InstructionBlock block2 in successors) { writer.WriteLine("\t\tblock {0}", block2.Index); } } } return writer.ToString(); }
public ReadWriteDependencyInjectorImpl(IList<XILSInstr> instrs): base(instrs) { _cfg = Compilation.CreateCFG(instrs); SetHandler(InstructionCodes.LoadVar, HandleLoadVar); SetHandler(InstructionCodes.StoreVar, HandleStoreVar); SetHandler(InstructionCodes.LdelemFixA, HandleLoadElement); SetHandler(InstructionCodes.LdelemFixAFixI, HandleLoadElement); SetHandler(InstructionCodes.StelemFixA, HandleStoreElement); SetHandler(InstructionCodes.StelemFixAFixI, HandleStoreElement); }
/// <summary> /// Computes a key sequence of the given CFG. /// </summary> /// <param name="graph">The CFG.</param> /// <param name="random">The random source, or <c>null</c> if key id is needed.</param> /// <returns>The generated key sequence of the CFG.</returns> public static BlockKey[] ComputeKeys(ControlFlowGraph graph, RandomGenerator random) { var keys = new BlockKey[graph.Count]; foreach (ControlFlowBlock block in graph) { var key = new BlockKey(); if ((block.Type & ControlFlowBlockType.Entry) != 0) key.Type = BlockKeyType.Explicit; else key.Type = BlockKeyType.Incremental; keys[block.Id] = key; } ProcessBlocks(keys, graph, random); return keys; }
public void Walk(MethodInfo method, ControlFlowGraph graph) { this.recorder = new CallParameterTypesRecorder(); this.recorder.Initialize(method); var variables = method.GetMethodBody().LocalVariables.ToDictionary(x => x.LocalIndex, x => PotentialType.FromType(x.LocalType)); var parameters = method.GetParameters().ToDictionary(x => x.Position, x => PotentialType.FromType(x.ParameterType)); var initialState = new TypeAnalysisState(variables, parameters); var walker = new ControlFlowGraphWalker<TypeAnalysisState> { InitialState = initialState, VisitingBlock = (state, block) => this.recorder.Visit(state, block.Instructions) }; walker.WalkCore(method, graph); }
public BlockStatement Process (DecompilationContext context, BlockStatement body) { this.cfg = context.ControlFlowGraph; this.annotations = AnnotationStore.CreateStore (cfg, optimization); this.body = context.Body; this.variables = context.Variables; this.expression_decompiler = new ExpressionDecompiler (context.Method, annotations); this.statements = new List<Statement> [cfg.Blocks.Length]; this.processed = new HashSet<InstructionBlock> (); this.assignments = new Dictionary<VariableReference, Expression> (); Run (); PopulateBodyBlock (body); return body; }
public void Analyze(ControlFlowGraph graph) { DBC.Pre(graph != null, "graph is null"); Profile.Start("Splicing"); var visited = new List<BasicBlock>(); foreach (BasicBlock root in graph.Roots) DoSpliceHandlers(m_instructions, root, visited); visited.Clear(); foreach (BasicBlock root in graph.Roots) DoSpliceNullCheck(m_instructions, root, visited); var data = new DataFlow<Lattice>(m_instructions, graph.Roots); m_skipped = data.Skipped; Profile.Stop("Splicing"); var functions = new Lattice.Functions(); Dictionary<BasicBlock, Lattice> lattices = data.Analyze(functions, m_initialState); Profile.Start("Post Transform"); m_states = new State[m_instructions.Length]; foreach (var entry in lattices) { BasicBlock block = entry.Key; if (block.Length > 0) { Lattice lattice = entry.Value; for (int index = block.First.Index; index <= block.Last.Index; ++index) // it'd be nice to assert that every index was set, but methods often have dead code so it's a little difficult { m_states[index] = lattice.State; lattice = lattice.Transform(index); } } } Profile.Stop("Post Transform"); for (int index = 0; index < m_instructions.Length; ++index) { Log.DebugLine(this, "{0:X2}: {1}", m_instructions[index].Untyped.Offset, m_states[index]); } }
public static void FormatControlFlowGraph (TextWriter writer, ControlFlowGraph cfg) { int id = 1; foreach (InstructionBlock block in cfg.Blocks) { writer.WriteLine ("block {0}:", id); writer.WriteLine ("\tbody:"); foreach (Instruction instruction in block) { writer.Write ("\t\t"); Formatter.WriteInstruction (writer, instruction); writer.WriteLine (); } InstructionBlock [] successors = block.Successors; if (successors.Length > 0) { writer.WriteLine ("\tsuccessors:"); foreach (InstructionBlock successor in successors) { writer.WriteLine ("\t\tblock {0}", GetBlockId (cfg, successor)); } } ++id; } }
public RangeAnalysis(ControlFlowGraph cfg) : base(cfg) { }
public BasicAnnotationBuilder(ControlFlowGraph cfg) : base(cfg) { }
public string Format(FormatOptions options) { var nl = Environment.NewLine; var sb = new StringBuilder(); var body = _methodDef.Body; var cfg = new ControlFlowGraph(body); SourceCodePosition lastSource = null; _dissassembly.Format = options; var embedSource = options.HasFlag(FormatOptions.EmbedSourceCode) || options.HasFlag(FormatOptions.EmbedSourcePositions); if (embedSource && _dissassembly.MethodEntry != null) { var pos = _mapFile.GetSourceCodePositions(_dissassembly.MethodEntry).FirstOrDefault(); if (pos != null) { sb.Append(" // ----- Source Code: "); sb.Append(pos.Document.Path); sb.Append(nl); } } foreach (var block in cfg) { if (options.HasFlag(FormatOptions.ShowControlFlow)) { sb.AppendFormat(" // ----- Entry [{0}] Exit [{1}]{2}", string.Join(", ", block.EntryBlocks.Select(x => _dissassembly.FormatAddress(x.Entry).Trim())), string.Join(", ", block.ExitBlocks.Select(x => _dissassembly.FormatAddress(x.Entry).Trim())), nl); } foreach (var i in block.Instructions) { if (embedSource) { var source = _dissassembly.FindSourceCode(i.Offset, false); if (source != null && lastSource != null && source.Document.Path != lastSource.Document.Path) { // print document name. sb.Append(" // ----- "); sb.Append(source.Document.Path); sb.Append(nl); lastSource = null; } if (source == null && lastSource != null) { sb.AppendLine(" // ----- (no source)"); } else if (source != null && (lastSource == null || !source.Position.EqualExceptOffset(lastSource.Position))) { if (options.HasFlag(FormatOptions.EmbedSourcePositions)) sb.AppendFormat(" // ----- Position: {0} - {1}{2}", source.Position.Start, source.Position.End, nl); if (options.HasFlag(FormatOptions.EmbedSourceCode)) { string[] lines = GetSourceCodeLines(source); if (lines != null) sb.AppendLine(" // " + string.Join(nl + " // ", lines)); } } lastSource = source; } sb.AppendLine(_dissassembly.FormatInstruction(i)); } } sb.AppendLine(); if (body.Exceptions.Any()) { sb.AppendLine("Exception handlers:"); foreach (var handler in body.Exceptions) { sb.AppendFormat("\t{0} - {1}{2}", _dissassembly.FormatAddress(handler.TryStart), _dissassembly.FormatAddress(handler.TryEnd), nl); foreach (var c in handler.Catches) { sb.AppendFormat("\t\t{0} => {1}{2}", c.Type, _dissassembly.FormatAddress(c.Instruction), nl); } if (handler.CatchAll != null) { sb.AppendFormat("\t\t{0} => {1}{2}", "<any>", _dissassembly.FormatAddress(handler.CatchAll), nl); } } sb.AppendLine(); } if (_mapFile != null) { var typeEntry = _mapFile.GetTypeByNewName(_methodDef.Owner.Fullname); if (typeEntry != null) { var methodEntry = typeEntry.FindDexMethod(_methodDef.Name, _methodDef.Prototype.ToSignature()); if (methodEntry != null) { _registersToVariableNames = new Dictionary<string, string>(); var validParameters = methodEntry.Parameters.Where(x => !string.IsNullOrEmpty(x.Name)).ToList(); if (validParameters.Any()) { sb.AppendLine("Parameters:"); foreach (var p in validParameters) { var registerName = _dissassembly.FormatRegister(p.Register); sb.AppendFormat("\t{0} (r{1}) -> {2}{3}", registerName, p.Register, p.Name, nl); if(!string.IsNullOrEmpty(p.Name)) _registersToVariableNames.Add(registerName, p.Name); } sb.AppendLine(); } var validVariables = methodEntry.Variables.Where(x => !string.IsNullOrEmpty(x.Name)).ToList(); if (validVariables.Any()) { sb.AppendLine("Variables:"); foreach (var p in validVariables) { var registerName = _dissassembly.FormatRegister(p.Register); sb.AppendFormat("\t{0} -> {1}{2}", registerName, p.Name, nl); if (!string.IsNullOrEmpty(p.Name)) _registersToVariableNames.Add(registerName, p.Name); } sb.AppendLine(); } sb.AppendLine("Source code positions:"); Document lastDocument = null; foreach (var row in _mapFile.GetSourceCodePositions(methodEntry)) { if (row.Document != lastDocument) { sb.AppendFormat("\t{0}{1}", row.Document.Path, nl); lastDocument = row.Document; } var pos = row.Position; sb.AppendFormat("\t{0}\t({1},{2}) - ({3},{4}){5}", MethodDisassembly.FormatOffset(pos.MethodOffset), pos.Start.Line, pos.Start.Column, pos.End.Line, pos.End.Column, nl); } } } } return sb.ToString(); }
private FlowGraphAnalysisData( ControlFlowGraph controlFlowGraph, ISymbol owningSymbol, ImmutableArray <IParameterSymbol> parameters, PooledDictionary <BasicBlock, BasicBlockAnalysisData> analysisDataByBasicBlockMap, PooledDictionary <(ISymbol symbol, IOperation operation), bool> symbolsWriteMap,
public static void FormatControlFlowGraph (TextWriter writer, ControlFlowGraph cfg) { foreach (InstructionBlock block in cfg.Blocks) { writer.WriteLine ("block {0}:", block.Index); writer.WriteLine ("\tbody:"); foreach (Instruction instruction in block) { writer.Write ("\t\t"); var data = cfg.GetData (instruction); writer.Write ("[{0}:{1}] ", data.StackBefore, data.StackAfter); Formatter.WriteInstruction (writer, instruction); writer.WriteLine (); } InstructionBlock [] successors = block.Successors; if (successors.Length > 0) { writer.WriteLine ("\tsuccessors:"); foreach (InstructionBlock successor in successors) { writer.WriteLine ("\t\tblock {0}", successor.Index); } } } }
public ZeroAnalysis(ControlFlowGraph cfg) : base(cfg) { }
public void ManyBlocks() { var TAC = GenerateTAC( @" { 1: a = b + c; d = b + c; b = b + c; t = b + c; a = d * e; if x { goto 1; } 3: o = d * e; a = d * e; if y { goto 3; } } "); var blocks = new TACBaseBlocks(TAC.Instructions); blocks.GenBaseBlocks(); var cfg = new ControlFlowGraph(blocks.blocks); var optimizer = new AvailableExpressionsOptimizer(); optimizer.Run(cfg, blocks.blocks); var actual = blocks.blocks.Select(b => b.ToString().Trim()); var expected = new List <string>() { "1\n" + "a = b + c\n" + "d = a\n" + "b = a\n" + "t = b + c\n" + "a = d * e\n" + "if x goto #L0", "goto #L1", "#L0\n" + "goto 1", "#L1", "3\n" + "o = a\n" + "a = a\n" + "if y goto #L2", "goto #L3", "#L2\n" + "goto 3", "#L3" }; Assert.AreEqual(actual, expected); }
private int InitialDepthOfBlock(CfgBlock block, ControlFlowGraph cfg) { int sd = block2depth[block.Index]; if (this.visited[block.Index]) return sd; this.visited[block.Index] = true; int depth; ExceptionHandler eh = cfg.HandlerThatStartsAtBlock(block); if (eh == null) { // if we haven't seen this block and it is not the entry block // nor the Exception Exit of the method // it is unreachable if (block == cfg.Entry) { depth = 0; } else if (block == cfg.ExceptionExit) { depth = 0; } else { depth = -1; } } else { switch (eh.HandlerType) { case NodeType.Catch: case NodeType.FaultHandler: case NodeType.Filter: depth = 1; break; case NodeType.Finally: depth = 0; break; default: throw new ApplicationException("unknown handler type"); } } block2depth[block.Index] = depth; return depth; }
public void ExplodedGraph_NonDecisionMakingAssignments() { string testInput = "var a = true; a |= false; var b = 42; b++; ++b;"; SemanticModel semanticModel; var method = ControlFlowGraphTest.CompileWithMethodBody(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var varDeclarators = method.DescendantNodes().OfType <VariableDeclaratorSyntax>(); var aSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "a")); var bSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "b")); var cfg = ControlFlowGraph.Create(method.Body, semanticModel); var lva = LiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new ExplodedGraph(cfg, methodSymbol, semanticModel, lva); SymbolicValue sv = null; var numberOfProcessedInstructions = 0; var branchesVisited = 0; explodedGraph.InstructionProcessed += (sender, args) => { numberOfProcessedInstructions++; if (args.Instruction.ToString() == "a = true") { branchesVisited++; Assert.IsTrue(args.ProgramState.GetSymbolValue(aSymbol) == SymbolicValue.True); } if (args.Instruction.ToString() == "a |= false") { branchesVisited++; Assert.IsNotNull(args.ProgramState.GetSymbolValue(aSymbol)); Assert.IsFalse(args.ProgramState.GetSymbolValue(aSymbol) == SymbolicValue.False); Assert.IsFalse(args.ProgramState.GetSymbolValue(aSymbol) == SymbolicValue.True); } if (args.Instruction.ToString() == "b = 42") { branchesVisited++; sv = args.ProgramState.GetSymbolValue(bSymbol); Assert.IsNotNull(sv); } if (args.Instruction.ToString() == "b++") { branchesVisited++; var svNew = args.ProgramState.GetSymbolValue(bSymbol); Assert.IsNotNull(svNew); Assert.AreNotEqual(sv, svNew); } if (args.Instruction.ToString() == "++b") { branchesVisited++; var svNew = args.ProgramState.GetSymbolValue(bSymbol); Assert.IsNotNull(svNew); Assert.AreNotEqual(sv, svNew); } }; explodedGraph.Walk(); Assert.AreEqual(11, numberOfProcessedInstructions); Assert.AreEqual(5, branchesVisited); }
public void ExplodedGraph_InternalStateCount_MaxReached() { var testInput = @" using System; namespace TesteAnalyzer { class Program { static bool GetBool() { return bool.Parse(""True""); } static void Main(string[] args) { bool corrupted = false; corrupted |= !GetBool(); corrupted |= !GetBool(); corrupted |= !GetBool(); corrupted |= !GetBool(); corrupted |= !GetBool(); corrupted |= !GetBool(); corrupted |= !GetBool(); corrupted |= !GetBool(); corrupted |= !GetBool(); corrupted |= !GetBool(); corrupted |= !GetBool(); corrupted |= !GetBool(); corrupted |= !GetBool(); corrupted |= !GetBool(); corrupted |= !GetBool(); corrupted |= !GetBool(); corrupted |= !GetBool(); if (!corrupted) { Console.Out.WriteLine(); } } } } "; SemanticModel semanticModel; var tree = ControlFlowGraphTest.Compile(testInput, out semanticModel); var method = tree.GetRoot().DescendantNodes().OfType <MethodDeclarationSyntax>().First(m => m.Identifier.ValueText == "Main"); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var cfg = ControlFlowGraph.Create(method.Body, semanticModel); var lva = LiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new ExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var maxStepCountReached = false; explodedGraph.MaxStepCountReached += (sender, args) => { maxStepCountReached = true; }; var maxInternalStateCountReached = false; explodedGraph.MaxInternalStateCountReached += (sender, args) => { maxInternalStateCountReached = true; }; explodedGraph.Walk(); Assert.IsFalse(explorationEnded); Assert.IsFalse(maxStepCountReached); Assert.IsTrue(maxInternalStateCountReached); }
public void ExplodedGraph_BothBranchesVisited() { string testInput = "var a = false; bool b; if (inParameter) { b = inParameter; } else { b = !inParameter; } a = b;"; SemanticModel semanticModel; var method = ControlFlowGraphTest.CompileWithMethodBody(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var varDeclarators = method.DescendantNodes().OfType <VariableDeclaratorSyntax>(); var aSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "a")); var bSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "b")); var parameters = method.DescendantNodes().OfType <ParameterSyntax>(); var inParameterSymbol = semanticModel.GetDeclaredSymbol(parameters.First(d => d.Identifier.ToString() == "inParameter")); var cfg = ControlFlowGraph.Create(method.Body, semanticModel); var lva = LiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new ExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var numberOfExitBlockReached = 0; explodedGraph.ExitBlockReached += (sender, args) => { numberOfExitBlockReached++; }; var numberOfLastInstructionVisits = 0; var numberOfProcessedInstructions = 0; var visitedBlocks = new HashSet <Block>(); var branchesVisited = 0; explodedGraph.InstructionProcessed += (sender, args) => { visitedBlocks.Add(args.ProgramPoint.Block); numberOfProcessedInstructions++; if (args.Instruction.ToString() == "a = false") { branchesVisited++; Assert.IsTrue(args.ProgramState.GetSymbolValue(aSymbol) == SymbolicValue.False); // Roslyn is clever !true has const value. } if (args.Instruction.ToString() == "b = inParameter") { branchesVisited++; Assert.IsTrue(bSymbol.HasConstraint(BoolConstraint.True, args.ProgramState)); Assert.IsTrue(inParameterSymbol.HasConstraint(BoolConstraint.True, args.ProgramState)); } if (args.Instruction.ToString() == "b = !inParameter") { branchesVisited++; // b has value, but not true or false Assert.IsNotNull(args.ProgramState.GetSymbolValue(bSymbol)); Assert.IsFalse(bSymbol.HasConstraint(BoolConstraint.False, args.ProgramState)); Assert.IsFalse(bSymbol.HasConstraint(BoolConstraint.True, args.ProgramState)); Assert.IsTrue(inParameterSymbol.HasConstraint(BoolConstraint.False, args.ProgramState)); } if (args.Instruction.ToString() == "a = b") { branchesVisited++; Assert.IsNull(args.ProgramState.GetSymbolValue(inParameterSymbol)); // not out/ref parameter and LVA says dead numberOfLastInstructionVisits++; } }; explodedGraph.Walk(); Assert.IsTrue(explorationEnded); Assert.AreEqual(4 + 1, branchesVisited); Assert.AreEqual(1, numberOfExitBlockReached, "All variables are dead at the ExitBlock, so whenever we get there, the ExplodedGraph nodes should be the same, " + "and thus should be processed only once."); Assert.AreEqual(2, numberOfLastInstructionVisits); Assert.AreEqual(cfg.Blocks.Count() - 1 /* Exit block */, visitedBlocks.Count); }
public void Analyze() { var graph = new ControlFlowGraph(m_instructions); Analyze(graph); }
/// <summary> /// Load the text to display /// </summary> protected override string LoadText(ISpyContext settings) { var nl = Environment.NewLine; var sb = new StringBuilder(); sb.AppendFormat("AccessFlags: {0}{1}", methodDef.AccessFlags, nl); sb.AppendFormat("Prototype: {0}{1}", methodDef.Prototype, nl); var body = methodDef.Body; if (body != null) { var cfg = new ControlFlowGraph(body); sb.AppendFormat("#Registers: {0}{1}", body.Registers.Count, nl); sb.AppendFormat("#Incoming: {0}{1}", body.IncomingArguments, nl); sb.AppendFormat("#Outgoing: {0}{1}", body.OutgoingArguments, nl); sb.AppendLine("Code:"); #if DEBUG var firstBlock = true; #endif foreach (var block in cfg) { #if DEBUG if (!firstBlock) { sb.AppendLine("\t----------------- "); } sb.AppendFormat("\tEntry [{0}], Exit [{1}]{2}", string.Join(", ", block.EntryBlocks.Select(x => x.Entry.Offset.ToString("x4"))), string.Join(", ", block.ExitBlocks.Select(x => x.Entry.Offset.ToString("x4"))), nl); firstBlock = false; #endif foreach (var i in block.Instructions) { sb.AppendFormat("\t{0:x4} {1} {2} {3}{4}", i.Offset, Format(i.OpCode), Register(i), FormatOperand(i.Operand), nl); } } sb.AppendLine(); if (body.Exceptions.Any()) { sb.AppendLine("Exception handlers:"); foreach (var handler in body.Exceptions) { sb.AppendFormat("\t{0:x4}-{1:x4}{2}", handler.TryStart.Offset, handler.TryEnd.Offset, nl); foreach (var c in handler.Catches) { sb.AppendFormat("\t\t{0} => {1:x4}{2}", c.Type, c.Instruction.Offset, nl); } if (handler.CatchAll != null) { sb.AppendFormat("\t\t{0} => {1:x4}{2}", "<any>", handler.CatchAll.Offset, nl); } } } var mapFile = settings.MapFile; if (mapFile != null) { var typeEntry = mapFile.GetTypeByNewName(methodDef.Owner.Fullname); if (typeEntry != null) { var methodEntry = typeEntry.FindDexMethod(methodDef.Name, methodDef.Prototype.ToSignature()); if (methodEntry != null) { var validParameters = methodEntry.Parameters.Where(x => !string.IsNullOrEmpty(x.Name)).ToList(); if (validParameters.Any()) { sb.AppendLine("Parameters:"); foreach (var p in validParameters) { sb.AppendFormat("\tr{0} -> {1}{2}", p.Register, p.Name, nl); } sb.AppendLine(); } var validVariables = methodEntry.Variables.Where(x => !string.IsNullOrEmpty(x.Name)).ToList(); if (validVariables.Any()) { sb.AppendLine("Variables:"); foreach (var p in validVariables) { sb.AppendFormat("\tr{0} -> {1}{2}", p.Register, p.Name, nl); } sb.AppendLine(); } sb.AppendLine("Source code:"); Document lastDocument = null; foreach (var row in mapFile.GetLocations(typeEntry, methodEntry)) { if (row.Item1 != lastDocument) { sb.AppendFormat("\t{0}{1}", row.Item1.Path, nl); lastDocument = row.Item1; } var pos = row.Item2; sb.AppendFormat("\t{0:x4}\t({1},{2}) - ({3},{4}){5}", pos.MethodOffset, pos.Start.Line, pos.Start.Column, pos.End.Line, pos.End.Column, nl); } } } } #if DEBUG var debugInfo = body.DebugInfo; if (debugInfo != null) { sb.AppendLine(); sb.AppendLine("DEX Debug info:"); sb.AppendFormat("\tStart line: {0}{1}", debugInfo.LineStart, nl); int lineNumber = (int) debugInfo.LineStart; var address = 0; var index = 0; foreach (var ins in debugInfo.DebugInstructions) { if (!ins.IsLowLevel) sb.AppendFormat("\t{0:x4}\tline {1}, address {2:x4} -> {3}{4}", index, lineNumber, address, ins, nl); ins.UpdateLineAndAddress(ref lineNumber, ref address); index++; } } #endif } return sb.ToString(); }
public static string ToString (ControlFlowGraph cfg) { StringWriter writer = new StringWriter (); FormatControlFlowGraph (writer, cfg); return writer.ToString (); }
static void ProcessBlocks(BlockKey[] keys, ControlFlowGraph graph, RandomGenerator random) { uint id = 0; for (int i = 0; i < keys.Length; i++) { keys[i].EntryState = id++; keys[i].ExitState = id++; } var finallyIds = new Dictionary<ExceptionHandler, uint>(); var ehMap = new Dictionary<ControlFlowBlock, List<ExceptionHandler>>(); bool updated; do { updated = false; // Update the state ids with the maximum id foreach (ControlFlowBlock block in graph) { BlockKey key = keys[block.Id]; if (block.Sources.Count > 0) { uint newEntry = block.Sources.Select(b => keys[b.Id].ExitState).Max(); if (key.EntryState != newEntry) { key.EntryState = newEntry; updated = true; } } if (block.Targets.Count > 0) { uint newExit = block.Targets.Select(b => keys[b.Id].EntryState).Max(); if (key.ExitState != newExit) { key.ExitState = newExit; updated = true; } } if (block.Footer.OpCode.Code == Code.Endfilter || block.Footer.OpCode.Code == Code.Endfinally) { // Match the exit state within finally/fault/filter List<ExceptionHandler> ehs; if (!ehMap.TryGetValue(block, out ehs)) { ehs = new List<ExceptionHandler>(); int footerIndex = graph.IndexOf(block.Footer); foreach (var eh in graph.Body.ExceptionHandlers) { if (eh.FilterStart != null && block.Footer.OpCode.Code == Code.Endfilter) { if (footerIndex >= graph.IndexOf(eh.FilterStart) && footerIndex < graph.IndexOf(eh.HandlerStart)) ehs.Add(eh); } else if (eh.HandlerType == ExceptionHandlerType.Finally || eh.HandlerType == ExceptionHandlerType.Fault) { if (footerIndex >= graph.IndexOf(eh.HandlerStart) && (eh.HandlerEnd == null || footerIndex < graph.IndexOf(eh.HandlerEnd))) ehs.Add(eh); } } ehMap[block] = ehs; } foreach (var eh in ehs) { uint ehVal; if (finallyIds.TryGetValue(eh, out ehVal)) { if (key.ExitState > ehVal) { finallyIds[eh] = key.ExitState; updated = true; } else if (key.ExitState < ehVal) { key.ExitState = ehVal; updated = true; } } else { finallyIds[eh] = key.ExitState; updated = true; } } } else if (block.Footer.OpCode.Code == Code.Leave || block.Footer.OpCode.Code == Code.Leave_S) { // Match the exit state with finally/fault/filter List<ExceptionHandler> ehs; if (!ehMap.TryGetValue(block, out ehs)) { ehs = new List<ExceptionHandler>(); int footerIndex = graph.IndexOf(block.Footer); foreach (var eh in graph.Body.ExceptionHandlers) { if (footerIndex >= graph.IndexOf(eh.TryStart) && (eh.TryEnd == null || footerIndex < graph.IndexOf(eh.TryEnd))) ehs.Add(eh); } ehMap[block] = ehs; } uint? maxVal = null; foreach (var eh in ehs) { uint ehVal; if (finallyIds.TryGetValue(eh, out ehVal) && (maxVal == null || ehVal > maxVal)) { if (maxVal != null) updated = true; maxVal = ehVal; } } if (maxVal != null) { if (key.ExitState > maxVal.Value) { maxVal = key.ExitState; updated = true; } else if (key.ExitState < maxVal.Value) { key.ExitState = maxVal.Value; updated = true; } foreach (var eh in ehs) finallyIds[eh] = maxVal.Value; } } keys[block.Id] = key; } } while (updated); if (random != null) { // Replace id with actual values var idMap = new Dictionary<uint, uint>(); for (int i = 0; i < keys.Length; i++) { BlockKey key = keys[i]; uint entryId = key.EntryState; if (!idMap.TryGetValue(entryId, out key.EntryState)) key.EntryState = idMap[entryId] = random.NextUInt32(); uint exitId = key.ExitState; if (!idMap.TryGetValue(exitId, out key.ExitState)) key.ExitState = idMap[exitId] = random.NextUInt32(); keys[i] = key; } } }
static int GetBlockId (ControlFlowGraph cfg, InstructionBlock block) { return ((IList<InstructionBlock>) cfg.Blocks).IndexOf (block) + 1; }
public static string Serialize(ControlFlowGraph cfg) { using (var stringWriter = new StringWriter()) using (var xmlWriter = new XmlTextWriter(stringWriter)) { xmlWriter.Formatting = Formatting.Indented; xmlWriter.WriteStartElement("DirectedGraph"); xmlWriter.WriteAttributeString("xmlns", "http://schemas.microsoft.com/vs/2009/dgml"); xmlWriter.WriteStartElement("Nodes"); foreach (var node in cfg.Nodes) { var nodeId = Convert.ToString(node.Id); var label = DGMLSerializer.Serialize(node); xmlWriter.WriteStartElement("Node"); xmlWriter.WriteAttributeString("Id", nodeId); xmlWriter.WriteAttributeString("Label", label); if (node.Kind == CFGNodeKind.Entry || node.Kind == CFGNodeKind.Exit) { xmlWriter.WriteAttributeString("Background", "Yellow"); } xmlWriter.WriteEndElement(); } xmlWriter.WriteEndElement(); xmlWriter.WriteStartElement("Links"); foreach (var node in cfg.Nodes) { var sourceId = Convert.ToString(node.Id); foreach (var successor in node.Successors) { var targetId = Convert.ToString(successor.Id); xmlWriter.WriteStartElement("Link"); xmlWriter.WriteAttributeString("Source", sourceId); xmlWriter.WriteAttributeString("Target", targetId); xmlWriter.WriteEndElement(); } } xmlWriter.WriteEndElement(); xmlWriter.WriteStartElement("Styles"); xmlWriter.WriteStartElement("Style"); xmlWriter.WriteAttributeString("TargetType", "Node"); xmlWriter.WriteStartElement("Setter"); xmlWriter.WriteAttributeString("Property", "FontFamily"); xmlWriter.WriteAttributeString("Value", "Consolas"); xmlWriter.WriteEndElement(); xmlWriter.WriteStartElement("Setter"); xmlWriter.WriteAttributeString("Property", "NodeRadius"); xmlWriter.WriteAttributeString("Value", "5"); xmlWriter.WriteEndElement(); xmlWriter.WriteStartElement("Setter"); xmlWriter.WriteAttributeString("Property", "MinWidth"); xmlWriter.WriteAttributeString("Value", "0"); xmlWriter.WriteEndElement(); xmlWriter.WriteEndElement(); xmlWriter.WriteEndElement(); xmlWriter.WriteEndElement(); xmlWriter.Flush(); return(stringWriter.ToString()); } }
private void Test(ControlFlowGraph graph, params string[] lines) { var sequences = graph.DeriveSequences(); Print(sequences); var spec = new TestSpec(); foreach (var line in lines) { spec.ReadLine(line); } spec.Test(graph, sequences); }
public TypeInferenceAnalysis(ControlFlowGraph cfg, ITypeReference returnType) { this.cfg = cfg; this.returnType = returnType; fixptCount = 0; }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.RegisterCompilationStartAction(compilationContext => { compilationContext.RegisterOperationBlockStartAction(operationBlockStartContext => { if (!(operationBlockStartContext.OwningSymbol is IMethodSymbol containingMethod)) { return; } foreach (var operationRoot in operationBlockStartContext.OperationBlocks) { IBlockOperation topmostBlock = operationRoot.GetTopmostParentBlock(); if (topmostBlock != null && topmostBlock.HasAnyOperationDescendant(op => (op as IBinaryOperation)?.IsComparisonOperator() == true || op.Kind == OperationKind.Coalesce || op.Kind == OperationKind.ConditionalAccess)) { var cfg = ControlFlowGraph.Create(topmostBlock); var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(operationBlockStartContext.Compilation); var nullAnalysisResult = NullAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider); var pointsToAnalysisResult = PointsToAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, nullAnalysisResult); var copyAnalysisResult = CopyAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, nullAnalysisResultOpt: nullAnalysisResult, pointsToAnalysisResultOpt: pointsToAnalysisResult); // Do another null analysis pass to improve the results from PointsTo and Copy analysis. nullAnalysisResult = NullAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, copyAnalysisResult, pointsToAnalysisResultOpt: pointsToAnalysisResult); var stringContentAnalysisResult = StringContentAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, copyAnalysisResult, nullAnalysisResult, pointsToAnalysisResult); operationBlockStartContext.RegisterOperationAction(operationContext => { PredicateValueKind GetPredicateKind(IBinaryOperation operation) { if (operation.IsComparisonOperator()) { PredicateValueKind binaryPredicateKind = nullAnalysisResult.GetPredicateKind(operation); if (binaryPredicateKind != PredicateValueKind.Unknown) { return(binaryPredicateKind); } binaryPredicateKind = copyAnalysisResult.GetPredicateKind(operation); if (binaryPredicateKind != PredicateValueKind.Unknown) { return(binaryPredicateKind); } binaryPredicateKind = stringContentAnalysisResult.GetPredicateKind(operation); if (binaryPredicateKind != PredicateValueKind.Unknown) { return(binaryPredicateKind); } ; } return(PredicateValueKind.Unknown); } var binaryOperation = (IBinaryOperation)operationContext.Operation; PredicateValueKind predicateKind = GetPredicateKind(binaryOperation); if (predicateKind != PredicateValueKind.Unknown && (!(binaryOperation.LeftOperand is IBinaryOperation leftBinary) || GetPredicateKind(leftBinary) == PredicateValueKind.Unknown) && (!(binaryOperation.RightOperand is IBinaryOperation rightBinary) || GetPredicateKind(rightBinary) == PredicateValueKind.Unknown)) { // '{0}' is always '{1}'. Remove or refactor the condition(s) to avoid dead code. var arg1 = binaryOperation.Syntax.ToString(); var arg2 = predicateKind == PredicateValueKind.AlwaysTrue ? (binaryOperation.Language == LanguageNames.VisualBasic ? "True" : "true") : (binaryOperation.Language == LanguageNames.VisualBasic ? "False" : "false"); var diagnostic = binaryOperation.CreateDiagnostic(AlwaysTrueFalseOrNullRule, arg1, arg2); operationContext.ReportDiagnostic(diagnostic); } }, OperationKind.BinaryOperator); operationBlockStartContext.RegisterOperationAction(operationContext => { IOperation nullCheckedOperation = operationContext.Operation.Kind == OperationKind.Coalesce ? ((ICoalesceOperation)operationContext.Operation).Value : ((IConditionalAccessOperation)operationContext.Operation).Operation; // '{0}' is always/never '{1}'. Remove or refactor the condition(s) to avoid dead code. DiagnosticDescriptor rule; switch (nullAnalysisResult[nullCheckedOperation]) { case NullAbstractValue.Null: rule = AlwaysTrueFalseOrNullRule; break; case NullAbstractValue.NotNull: rule = NeverNullRule; break; default: return; } var arg1 = nullCheckedOperation.Syntax.ToString(); var arg2 = nullCheckedOperation.Language == LanguageNames.VisualBasic ? "Nothing" : "null"; var diagnostic = nullCheckedOperation.CreateDiagnostic(rule, arg1, arg2); operationContext.ReportDiagnostic(diagnostic); }, OperationKind.Coalesce, OperationKind.ConditionalAccess); } } }); }); }
public Analyzer(ControlFlowGraph cfg, string loopIndex) : base(cfg) { ExtremalValues = _CreateExtremalValues(cfg, loopIndex); }
/// <summary> /// Parses the given <see cref="ControlFlowGraph{TInstruction}"/> /// </summary> /// <returns>A <see cref="ControlFlowGraph{TInstruction}"/> representing the Ast</returns> public ControlFlowGraph <Statement <TInstruction> > Parse() { var newGraph = new ControlFlowGraph <Statement <TInstruction> >(_architecture); var rootScope = _controlFlowGraph.ConstructBlocks(); // Transform and add regions. foreach (var originalRegion in _controlFlowGraph.Regions) { var newRegion = TransformRegion(originalRegion); newGraph.Regions.Add(newRegion); } // Transform and add nodes. foreach (var originalBlock in rootScope.GetAllBlocks()) { var originalNode = _controlFlowGraph.Nodes[originalBlock.Offset]; var transformedBlock = _transformer.Transform(originalBlock); var newNode = new ControlFlowNode <Statement <TInstruction> >(originalBlock.Offset, transformedBlock); newGraph.Nodes.Add(newNode); // Move node to newly created region. if (originalNode.ParentRegion is ScopeRegion <TInstruction> basicRegion) { newNode.MoveToRegion(_regionsMapping[basicRegion]); } } // Clone edges. foreach (var originalEdge in _controlFlowGraph.GetEdges()) { var newOrigin = newGraph.Nodes[originalEdge.Origin.Offset]; var newTarget = newGraph.Nodes[originalEdge.Target.Offset]; newOrigin.ConnectWith(newTarget, originalEdge.Type); } // Fix entry point(s). newGraph.Entrypoint = newGraph.Nodes[_controlFlowGraph.Entrypoint.Offset]; FixEntryPoint(_controlFlowGraph); return(newGraph); void FixEntryPoint(IControlFlowRegion <TInstruction> region) { foreach (var child in region.GetSubRegions()) { FixEntryPoint(child); } if (!(region is ScopeRegion <TInstruction> basicControlFlowRegion)) { return; } var entry = basicControlFlowRegion.Entrypoint; if (entry is null) { return; } _regionsMapping[basicControlFlowRegion].Entrypoint = newGraph.Nodes[entry.Offset]; } }
private List<Conditional> TestConditionals(ControlFlowGraph graph, params string[] args) { graph.SortByDepthFirstPostOrder(); graph.StructureLoops(); var conditionals = graph.StructureConditionals(); const string fmt = "{0}: {1}"; var lines = conditionals.Select((x, i) => { var str = string.Format(fmt, i, x); Console.WriteLine(str); return str; }).ToArray(); Assert.AreEqual(conditionals.Count, args.Length); for (int i = 0; i < args.Length; i++) { var expected = args[i]; var actual = lines[i]; Assert.AreEqual(expected, actual); } return conditionals; }
public Analyzer(ControlFlowGraph cfg) : base(cfg) { }
public BlockGenerator(ControlFlowGraph cfg, CilCodeGenerator generator) { _cfg = cfg ?? throw new ArgumentNullException(nameof(cfg)); _generator = generator; }
public ZCompilerResult Compile() { var sw = Stopwatch.StartNew(); var dm = CreateDynamicMethod(routine); this.il = new ILBuilder(dm.GetILGenerator()); this.calls = new List <ZRoutineCall>(); Profiler_EnterRoutine(); this.controlFlowGraph = ControlFlowGraph.Build(this.routine); this.addressToLabelMap = new Dictionary <int, ILabel>(this.controlFlowGraph.CodeBlocks.Count()); // Determine whether stack, memory, screen and outputStreams are used. foreach (var codeBlock in this.controlFlowGraph.CodeBlocks) { this.addressToLabelMap.Add(codeBlock.Address, il.NewLabel()); foreach (var i in codeBlock.Instructions) { if (!this.usesStack && i.UsesStack()) { this.usesStack = true; } if (!this.usesMemory && i.UsesMemory()) { this.usesMemory = true; } } } var instructionStatistics = new List <InstructionStatistics>(this.routine.Instructions.Length); // Emit IL foreach (var codeBlock in this.controlFlowGraph.CodeBlocks) { var generators = codeBlock.Instructions .Select(i => OpcodeGenerator.GetGenerator(i, machine.Version)) .ToList(); Optimize(generators); foreach (var generator in generators) { ILabel label; if (this.addressToLabelMap.TryGetValue(generator.Instruction.Address, out label)) { label.Mark(); } if (machine.Debugging) { il.Arguments.LoadMachine(); il.Call(Reflection <CompiledZMachine> .GetMethod("Tick", @public: false)); } Profiler_ExecutingInstruction(generator.Instruction); il.DebugWrite(generator.Instruction.PrettyPrint(machine)); var offset = il.Size; generator.Generate(il, this); instructionStatistics.Add(new InstructionStatistics(generator.Instruction, offset, il.Size - offset)); } } var code = (ZRoutineCode)dm.CreateDelegate(typeof(ZRoutineCode), machine); sw.Stop(); var statistics = new RoutineCompilationStatistics( this.routine, il.OpcodeCount, il.LocalCount, il.Size, sw.Elapsed, calculatedLoadVariableCount, calculatedStoreVariableCount, instructionStatistics); return(new ZCompilerResult(this.routine, calls.ToArray(), code, statistics)); }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.RegisterCompilationStartAction(compilationContext => { INamedTypeSymbol localizableStateAttributeSymbol = WellKnownTypes.LocalizableAttribute(compilationContext.Compilation); INamedTypeSymbol conditionalAttributeSymbol = WellKnownTypes.ConditionalAttribute(compilationContext.Compilation); INamedTypeSymbol systemConsoleSymbol = WellKnownTypes.Console(compilationContext.Compilation); ImmutableHashSet <INamedTypeSymbol> typesToIgnore = GetTypesToIgnore(compilationContext.Compilation); compilationContext.RegisterOperationBlockStartAction(operationBlockStartContext => { if (!(operationBlockStartContext.OwningSymbol is IMethodSymbol containingMethod)) { return; } var lazyStringContentResult = new Lazy <DataFlowAnalysisResult <StringContentBlockAnalysisResult, StringContentAbstractValue> >( valueFactory: ComputeStringContentAnalysisResult, isThreadSafe: false); operationBlockStartContext.RegisterOperationAction(operationContext => { var argument = (IArgumentOperation)operationContext.Operation; switch (argument.Parent?.Kind) { case OperationKind.Invocation: case OperationKind.ObjectCreation: AnalyzeArgument(argument.Parameter, containingPropertySymbolOpt: null, operation: argument, reportDiagnostic: operationContext.ReportDiagnostic); return; } }, OperationKind.Argument); operationBlockStartContext.RegisterOperationAction(operationContext => { var propertyReference = (IPropertyReferenceOperation)operationContext.Operation; if (propertyReference.Parent is IAssignmentOperation assignment && assignment.Target == propertyReference && !propertyReference.Property.IsIndexer && propertyReference.Property.SetMethod?.Parameters.Length == 1) { IParameterSymbol valueSetterParam = propertyReference.Property.SetMethod.Parameters[0]; AnalyzeArgument(valueSetterParam, propertyReference.Property, assignment, operationContext.ReportDiagnostic); } }, OperationKind.PropertyReference); void AnalyzeArgument(IParameterSymbol parameter, IPropertySymbol containingPropertySymbolOpt, IOperation operation, Action <Diagnostic> reportDiagnostic) { if (ShouldBeLocalized(parameter, containingPropertySymbolOpt, localizableStateAttributeSymbol, conditionalAttributeSymbol, systemConsoleSymbol, typesToIgnore)) { StringContentAbstractValue stringContentValue = lazyStringContentResult.Value[operation]; if (stringContentValue.IsLiteralState) { Debug.Assert(stringContentValue.LiteralValues.Count > 0); // FxCop compat: Do not fire if the literal value came from a default parameter value if (stringContentValue.LiteralValues.Count == 1 && parameter.IsOptional && parameter.ExplicitDefaultValue is string defaultValue && defaultValue == stringContentValue.LiteralValues.Single()) { return; } // FxCop compat: Do not fire if none of the string literals have any non-control character. if (!LiteralValuesHaveNonControlCharacters(stringContentValue.LiteralValues)) { return; } // FxCop compat: Filter out xml string literals. var filteredStrings = stringContentValue.LiteralValues.Where(literal => !LooksLikeXmlTag(literal)); if (filteredStrings.Any()) { // Method '{0}' passes a literal string as parameter '{1}' of a call to '{2}'. Retrieve the following string(s) from a resource table instead: "{3}". var arg1 = containingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat); var arg2 = parameter.Name; var arg3 = parameter.ContainingSymbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat); var arg4 = FormatLiteralValues(filteredStrings); var diagnostic = operation.CreateDiagnostic(Rule, arg1, arg2, arg3, arg4); reportDiagnostic(diagnostic); } } } } DataFlowAnalysisResult <StringContentBlockAnalysisResult, StringContentAbstractValue> ComputeStringContentAnalysisResult() { foreach (var operationRoot in operationBlockStartContext.OperationBlocks) { IBlockOperation topmostBlock = operationRoot.GetTopmostParentBlock(); if (topmostBlock != null) { var cfg = ControlFlowGraph.Create(topmostBlock); var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(operationBlockStartContext.Compilation); var pointsToAnalysisResult = PointsToAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider); var copyAnalysisResult = CopyAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, pointsToAnalysisResultOpt: pointsToAnalysisResult); // Do another analysis pass to improve the results from PointsTo and Copy analysis. pointsToAnalysisResult = PointsToAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, pointsToAnalysisResult, copyAnalysisResult); return(StringContentAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, copyAnalysisResult, pointsToAnalysisResult)); } } return(null); } }); }); }
/// <summary> /// Creates a new Ast parser with the given <see cref="ControlFlowGraph{TInstruction}"/> /// </summary> /// <param name="controlFlowGraph">The <see cref="ControlFlowGraph{TInstruction}"/> to parse</param> /// <param name="dataFlowGraph">The <see cref="DataFlowGraph{TContents}"/> to parse</param> public AstParser(ControlFlowGraph <TInstruction> controlFlowGraph, DataFlowGraph <TInstruction> dataFlowGraph) { var isa = new AstArchitecture <TInstruction>(controlFlowGraph.Architecture); _context = new AstParserContext <TInstruction>(controlFlowGraph, dataFlowGraph, isa); }
public static void Main() { var FileName = @"../../a.txt"; try { var Text = File.ReadAllText(FileName); var scanner = new Scanner(); scanner.SetSource(Text, 0); var parser = new Parser(scanner); var b = parser.Parse(); if (!b) { Console.WriteLine("Error"); } else { Console.WriteLine("Syntax tree built"); var fillParents = new FillParentsVisitor(); parser.root.Visit(fillParents); var pp = new PrettyPrintVisitor(); parser.root.Visit(pp); Console.WriteLine(pp.Text); ASTOptimizer.Optimize(parser); Console.WriteLine("\n\nAfter AST optimizations"); pp = new PrettyPrintVisitor(); parser.root.Visit(pp); Console.WriteLine(pp.Text); Console.WriteLine("\n\nThree address code"); var threeAddrCodeVisitor = new ThreeAddrGenVisitor(); parser.root.Visit(threeAddrCodeVisitor); var threeAddressCode = threeAddrCodeVisitor.Instructions; foreach (var instruction in threeAddressCode) { Console.WriteLine(instruction); } Console.WriteLine("\n\nOptimized three address code"); var optResult = ThreeAddressCodeOptimizer.OptimizeAll(threeAddressCode); foreach (var x in optResult) { Console.WriteLine(x); } Console.WriteLine("\n\nDivided three address code"); var divResult = BasicBlockLeader.DivideLeaderToLeader(optResult); foreach (var x in divResult) { foreach (var y in x.GetInstructions()) { Console.WriteLine(y); } Console.WriteLine("--------------"); } var cfg = new ControlFlowGraph(divResult); Console.WriteLine("\n\n Edge Classification"); Console.WriteLine("----------"); foreach (var pair in cfg.ClassifiedEdges) { Console.WriteLine(pair); } Console.WriteLine("----------"); foreach (var block in cfg.GetCurrentBasicBlocks()) { Console.WriteLine($"{cfg.VertexOf(block)} {block.GetInstructions().First()}"); var children = cfg.GetChildrenBasicBlocks(cfg.VertexOf(block)); var childrenStr = string.Join(" | ", children.Select(v => v.block.GetInstructions().First().ToString())); Console.WriteLine($" children: {childrenStr}"); var parents = cfg.GetParentsBasicBlocks(cfg.VertexOf(block)); var parentsStr = string.Join(" | ", parents.Select(v => v.block.GetInstructions().First().ToString())); Console.WriteLine($" parents: {parentsStr}"); } /// /// LiveVariableAnalysisAlgorithm /// Console.WriteLine("------------"); Console.WriteLine(); var activeVariable = new LiveVariables(); var resActiveVariable = activeVariable.Execute(cfg); foreach (var x in resActiveVariable) { foreach (var y in x.Value.In) { Console.WriteLine("In " + y); } Console.WriteLine(); foreach (var y in x.Value.Out) { Console.WriteLine("Out " + y); } } Console.WriteLine(); Console.WriteLine(); Console.WriteLine("NatLoop"); var natLoops = NaturalLoop.GetAllNaturalLoops(cfg); foreach (var x in natLoops) { if (x.Count == 0) { continue; } //Console.WriteLine("Loop"); for (var i = 0; i < x.Count; i++) { Console.WriteLine("NumberBlock:" + i); foreach (var xfrom in x[i].GetInstructions()) { Console.WriteLine(xfrom.ToString()); } } Console.WriteLine(); Console.WriteLine("-------------"); } Console.WriteLine(" \nDone"); } } catch (FileNotFoundException) { Console.WriteLine("File {0} not found", FileName); } catch (LexException e) { Console.WriteLine("Lex Error. " + e.Message); } catch (SyntaxException e) { Console.WriteLine("Syntax Error. " + e.Message); } Console.ReadLine(); }
public Analyzer(ControlFlowGraph cfg, string loopIndex, CallGraph callGraph, IEnumerable <ControlFlowGraph> procedures) : base(cfg, callGraph, procedures) { ExtremalValues = _CreateExtremalValues(cfg, loopIndex); }
private void InitializeReachabilityInfo(ControlFlowGraph x) { _visitedColor = x.NewColor(); }
private static TaintedDataAnalysisResult?TryGetOrComputeResult( ControlFlowGraph cfg, Compilation compilation, ISymbol containingMethod, AnalyzerOptions analyzerOptions, TaintedDataSymbolMap <SourceInfo> taintedSourceInfos, TaintedDataSymbolMap <SanitizerInfo> taintedSanitizerInfos, TaintedDataSymbolMap <SinkInfo> taintedSinkInfos, InterproceduralAnalysisConfiguration interproceduralAnalysisConfig) { if (cfg == null) { Debug.Fail("Expected non-null CFG"); return(null); } WellKnownTypeProvider wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation); ValueContentAnalysisResult?valueContentAnalysisResult = null; CopyAnalysisResult? copyAnalysisResult = null; PointsToAnalysisResult? pointsToAnalysisResult = null; if (taintedSourceInfos.RequiresValueContentAnalysis || taintedSanitizerInfos.RequiresValueContentAnalysis || taintedSinkInfos.RequiresValueContentAnalysis) { valueContentAnalysisResult = ValueContentAnalysis.TryGetOrComputeResult( cfg, containingMethod, analyzerOptions, wellKnownTypeProvider, PointsToAnalysisKind.Complete, interproceduralAnalysisConfig, out copyAnalysisResult, out pointsToAnalysisResult, pessimisticAnalysis: true, performCopyAnalysis: false); if (valueContentAnalysisResult == null) { return(null); } } else { pointsToAnalysisResult = PointsToAnalysis.TryGetOrComputeResult( cfg, containingMethod, analyzerOptions, wellKnownTypeProvider, PointsToAnalysisKind.Complete, interproceduralAnalysisConfig, interproceduralAnalysisPredicate: null, pessimisticAnalysis: true, performCopyAnalysis: false); if (pointsToAnalysisResult == null) { return(null); } } TaintedDataAnalysisContext analysisContext = TaintedDataAnalysisContext.Create( TaintedDataAbstractValueDomain.Default, wellKnownTypeProvider, cfg, containingMethod, analyzerOptions, interproceduralAnalysisConfig, pessimisticAnalysis: false, copyAnalysisResult: copyAnalysisResult, pointsToAnalysisResult: pointsToAnalysisResult, valueContentAnalysisResult: valueContentAnalysisResult, tryGetOrComputeAnalysisResult: TryGetOrComputeResultForAnalysisContext, taintedSourceInfos: taintedSourceInfos, taintedSanitizerInfos: taintedSanitizerInfos, taintedSinkInfos: taintedSinkInfos); return(TryGetOrComputeResultForAnalysisContext(analysisContext)); }
public static (ControlFlowGraph, string) Decompile(ControlFlowGraph graph) { if (graph == null) { throw new ArgumentNullException(nameof(graph)); } foreach (var head in graph.GetDfsPostOrder()) { var(trueChild, falseChild) = graph.GetBinaryChildren(head); if (!trueChild.HasValue || !falseChild.HasValue) { continue; } var left = trueChild.Value; var right = falseChild.Value; // Func<string> vis = () => graph.ToVis().AddPointer("head", head).AddPointer("after", after).AddPointer("left", left).AddPointer("right", right).ToString(); // For VS Code debug visualisation var leftParents = graph.Parents(left); var rightParents = graph.Parents(right); var leftChildren = graph.Children(left); var rightChildren = graph.Children(right); if (leftParents.Length != 1 || rightParents.Length != 1) // Branches of an if can't be jump destinations from elsewhere { continue; } bool isRegularIfThenElse = leftChildren.Length == 1 && rightChildren.Length == 1 && leftChildren[0] == rightChildren[0]; bool isTerminalIfThenElse = leftChildren.Length == 0 && rightChildren.Length == 0; if (!isRegularIfThenElse && !isTerminalIfThenElse) { continue; } var after = isRegularIfThenElse ? leftChildren[0] : -1; if (after == head) { continue; } var newNode = Emit.IfElse( graph.Nodes[head], graph.Nodes[left], graph.Nodes[right]); var updated = graph; if (isRegularIfThenElse) { updated = updated.AddEdge(head, after, CfgEdge.True); } return(updated .RemoveNode(left) .RemoveNode(right) .ReplaceNode(head, newNode), Description); } return(graph, null); }
protected AnnotationStoreBuilder(ControlFlowGraph cfg) { this.cfg = cfg; this.store = new AnnotationStore(); }
/// <summary> /// Analyzers should use BatchGetOrComputeHazardousUsages instead. Gets hazardous usages of an object based on a set of its properties. /// </summary> /// <param name="cfg">Control flow graph of the code.</param> /// <param name="compilation">Compilation containing the code.</param> /// <param name="owningSymbol">Symbol of the code to examine.</param> /// <param name="typeToTrackMetadataNames">Names of the types to track.</param> /// <param name="constructorMapper">How constructor invocations map to <see cref="PropertySetAbstractValueKind"/>s.</param> /// <param name="propertyMappers">How property assignments map to <see cref="PropertySetAbstractValueKind"/>.</param> /// <param name="hazardousUsageEvaluators">When and how to evaluate <see cref="PropertySetAbstractValueKind"/>s to for hazardous usages.</param> /// <param name="interproceduralAnalysisConfig">Interprocedural dataflow analysis configuration.</param> /// <param name="pessimisticAnalysis">Whether to be pessimistic.</param> /// <returns>Property set analysis result.</returns> internal static PropertySetAnalysisResult?GetOrComputeResult( ControlFlowGraph cfg, Compilation compilation, ISymbol owningSymbol, AnalyzerOptions analyzerOptions, ImmutableHashSet <string> typeToTrackMetadataNames, ConstructorMapper constructorMapper, PropertyMapperCollection propertyMappers, HazardousUsageEvaluatorCollection hazardousUsageEvaluators, InterproceduralAnalysisConfiguration interproceduralAnalysisConfig, bool pessimisticAnalysis = false) { if (constructorMapper == null) { throw new ArgumentNullException(nameof(constructorMapper)); } if (propertyMappers == null) { throw new ArgumentNullException(nameof(propertyMappers)); } if (hazardousUsageEvaluators == null) { throw new ArgumentNullException(nameof(hazardousUsageEvaluators)); } constructorMapper.Validate(propertyMappers.PropertyValuesCount); var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation); PointsToAnalysisResult? pointsToAnalysisResult; ValueContentAnalysisResult?valueContentAnalysisResultOpt; if (!constructorMapper.RequiresValueContentAnalysis && !propertyMappers.RequiresValueContentAnalysis) { pointsToAnalysisResult = PointsToAnalysis.TryGetOrComputeResult( cfg, owningSymbol, analyzerOptions, wellKnownTypeProvider, PointsToAnalysisKind.Complete, interproceduralAnalysisConfig, interproceduralAnalysisPredicateOpt: null, pessimisticAnalysis, performCopyAnalysis: false); if (pointsToAnalysisResult == null) { return(null); } valueContentAnalysisResultOpt = null; } else { valueContentAnalysisResultOpt = ValueContentAnalysis.TryGetOrComputeResult( cfg, owningSymbol, analyzerOptions, wellKnownTypeProvider, PointsToAnalysisKind.Complete, interproceduralAnalysisConfig, out var copyAnalysisResult, out pointsToAnalysisResult, pessimisticAnalysis, performCopyAnalysis: false); if (valueContentAnalysisResultOpt == null) { return(null); } } var analysisContext = PropertySetAnalysisContext.Create( PropertySetAbstractValueDomain.Default, wellKnownTypeProvider, cfg, owningSymbol, analyzerOptions, interproceduralAnalysisConfig, pessimisticAnalysis, pointsToAnalysisResult, valueContentAnalysisResultOpt, TryGetOrComputeResultForAnalysisContext, typeToTrackMetadataNames, constructorMapper, propertyMappers, hazardousUsageEvaluators); var result = TryGetOrComputeResultForAnalysisContext(analysisContext); return(result); }
/// <summary> /// Transform the given body. /// </summary> public bool Transform(Dex target, MethodBody body) { // Build the control flow graph var cfg = new ControlFlowGraph(body); // Go over each block to find registers that are initialized and may need initialization foreach (var iterator in cfg) { var block = iterator; var data = new BasicBlockData(block); block.Tag = data; // Go over all instructions in the block, finding source/destination registers foreach (var ins in block.Instructions) { var info = OpCodeInfo.Get(ins.Code.ToDex()); var count = ins.Registers.Count; for (var i = 0; i < count; i++) { var reg = ins.Registers[i]; if (reg.Category != RCategory.Argument) { var flags = info.GetUsage(i); if (flags.HasFlag(RegisterFlags.Source)) { // Must be initialize if (!data.Initialized.Contains(reg)) { data.MayNeedInitialization.Add(reg); } } if (flags.HasFlag(RegisterFlags.Destination)) { // Destination data.Initialized.Add(reg); } } } } } // Go over all blocks to collect the register that really need initialization var needInitialization = new HashSet<Register>(); foreach (var iterator in cfg) { var block = iterator; var data = (BasicBlockData)block.Tag; foreach (var regIterator in data.MayNeedInitialization) { // Short cut var reg = regIterator; if (needInitialization.Contains(reg)) continue; // If the register is initialized in all entry blocks, we do not need to initialize it if (block.EntryBlocks.Select(x => (BasicBlockData) x.Tag).Any(x => !x.IsInitialized(reg))) { // There is an entry block that does not initialize the register, so we have to initialize it needInitialization.Add(reg); } } } var index = 0; Register valueReg = null; Register objectReg = null; Register wideReg = null; var firstSourceLocation = body.Instructions[0].SequencePoint; foreach (var reg in needInitialization.OrderBy(x => x.Index)) { switch (reg.Type) { case RType.Value: if (valueReg == null) { body.Instructions.Insert(index++, new Instruction(RCode.Const, 0, new[] {reg}) { SequencePoint = firstSourceLocation }); valueReg = reg; } else if (valueReg != reg) { body.Instructions.Insert(index++, new Instruction(RCode.Move, reg, valueReg) { SequencePoint = firstSourceLocation }); } break; case RType.Object: if (objectReg == null) { body.Instructions.Insert(index++, new Instruction(RCode.Const, 0, new[] { reg }) { SequencePoint = firstSourceLocation }); objectReg = reg; } else if (objectReg != reg) { body.Instructions.Insert(index++, new Instruction(RCode.Move_object, reg, objectReg) { SequencePoint = firstSourceLocation }); } break; case RType.Wide: if (wideReg == null) { body.Instructions.Insert(index++, new Instruction(RCode.Const_wide, 0, new[] { reg }) { SequencePoint = firstSourceLocation }); wideReg = reg; } else if (wideReg != reg) { body.Instructions.Insert(index++, new Instruction(RCode.Move_wide, reg, wideReg) { SequencePoint = firstSourceLocation }); } break; } } return false; }
public static void RestorePopRanges(ControlFlowGraph graph) { List <ExceptionDeobfuscator.Range> lstRanges = new List <ExceptionDeobfuscator.Range >(); // aggregate ranges foreach (ExceptionRangeCFG range in graph.GetExceptions()) { bool found = false; foreach (ExceptionDeobfuscator.Range arr in lstRanges) { if (arr.handler == range.GetHandler() && InterpreterUtil.EqualObjects(range.GetUniqueExceptionsString (), arr.uniqueStr)) { Sharpen.Collections.AddAll(arr.protectedRange, range.GetProtectedRange()); found = true; break; } } if (!found) { // doesn't matter, which range chosen lstRanges.Add(new ExceptionDeobfuscator.Range(range.GetHandler(), range.GetUniqueExceptionsString (), new HashSet <BasicBlock>(range.GetProtectedRange()), range)); } } // process aggregated ranges foreach (ExceptionDeobfuscator.Range range in lstRanges) { if (range.uniqueStr != null) { BasicBlock handler = range.handler; InstructionSequence seq = handler.GetSeq(); Instruction firstinstr; if (seq.Length() > 0) { firstinstr = seq.GetInstr(0); if (firstinstr.opcode == ICodeConstants.opc_pop || firstinstr.opcode == ICodeConstants .opc_astore) { HashSet <BasicBlock> setrange = new HashSet <BasicBlock>(range.protectedRange); foreach (ExceptionDeobfuscator.Range range_super in lstRanges) { // finally or strict superset if (range != range_super) { HashSet <BasicBlock> setrange_super = new HashSet <BasicBlock>(range_super.protectedRange ); if (!setrange.Contains(range_super.handler) && !setrange_super.Contains(handler) && (range_super.uniqueStr == null || setrange.All(setrange_super.Contains))) { if (range_super.uniqueStr == null) { setrange_super.IntersectWith(setrange); } else { setrange_super.ExceptWith(setrange); } if (!(setrange_super.Count == 0)) { BasicBlock newblock = handler; // split the handler if (seq.Length() > 1) { newblock = new BasicBlock(++graph.last_id); InstructionSequence newseq = new SimpleInstructionSequence(); newseq.AddInstruction(firstinstr.Clone(), -1); newblock.SetSeq(newseq); graph.GetBlocks().AddWithKey(newblock, newblock.id); List <BasicBlock> lstTemp = new List <BasicBlock>(); Sharpen.Collections.AddAll(lstTemp, handler.GetPreds()); Sharpen.Collections.AddAll(lstTemp, handler.GetPredExceptions()); // replace predecessors foreach (BasicBlock pred in lstTemp) { pred.ReplaceSuccessor(handler, newblock); } // replace handler foreach (ExceptionRangeCFG range_ext in graph.GetExceptions()) { if (range_ext.GetHandler() == handler) { range_ext.SetHandler(newblock); } else if (range_ext.GetProtectedRange().Contains(handler)) { newblock.AddSuccessorException(range_ext.GetHandler()); range_ext.GetProtectedRange().Add(newblock); } } newblock.AddSuccessor(handler); if (graph.GetFirst() == handler) { graph.SetFirst(newblock); } // remove the first pop in the handler seq.RemoveInstruction(0); } newblock.AddSuccessorException(range_super.handler); range_super.rangeCFG.GetProtectedRange().Add(newblock); handler = range.rangeCFG.GetHandler(); seq = handler.GetSeq(); } } } } } } } } }
public _IIGraph_314(ControlFlowGraph graph) { this.graph = graph; }
private static bool SplitExceptionRange(ExceptionRangeCFG range, HashSet <BasicBlock > setEntries, ControlFlowGraph graph, GenericDominatorEngine engine) { foreach (BasicBlock entry in setEntries) { List <BasicBlock> lstSubrangeBlocks = GetReachableBlocksRestricted(entry, range, engine); if (!(lstSubrangeBlocks.Count == 0) && lstSubrangeBlocks.Count < range.GetProtectedRange ().Count) { // add new range ExceptionRangeCFG subRange = new ExceptionRangeCFG(lstSubrangeBlocks, range.GetHandler (), range.GetExceptionTypes()); graph.GetExceptions().Add(subRange); // shrink the original range lstSubrangeBlocks.ForEach(block => range.GetProtectedRange().Remove(block)); return(true); } else { // should not happen DecompilerContext.GetLogger().WriteMessage("Inconsistency found while splitting protected range" , IFernflowerLogger.Severity.Warn); } } return(false); }
private StackRemovalTransformation(ControlFlowGraph cfg) { this.block2depth = new int[cfg.BlockCount]; this.visited = new bool[cfg.BlockCount]; // initialize everything to unreachable for (int j=0; j<block2depth.Length; j++) { block2depth[j] = -1; } }
/// <summary> /// Reduce Nesting in switch statements by replacing break; in cases with the block exit, and extracting the default case /// Does not affect IL order /// </summary> private bool ReduceSwitchNesting(Block parentBlock, BlockContainer switchContainer, ILInstruction exitInst) { // break; from outer container cannot be brought inside the switch as the meaning would change if (exitInst is Leave leave && !leave.IsLeavingFunction) { return(false); } // find the default section, and ensure it has only one incoming edge var switchInst = (SwitchInstruction)switchContainer.EntryPoint.Instructions.Single(); var defaultSection = switchInst.Sections.MaxBy(s => s.Labels.Count()); if (!defaultSection.Body.MatchBranch(out var defaultBlock) || defaultBlock.IncomingEdgeCount != 1) { return(false); } // tally stats for heuristic from each case block int maxStatements = 0, maxDepth = 0; foreach (var section in switchInst.Sections) { if (section != defaultSection && section.Body.MatchBranch(out var caseBlock) && caseBlock.Parent == switchContainer) { UpdateStats(caseBlock, ref maxStatements, ref maxDepth); } } if (!ShouldReduceNesting(defaultBlock, maxStatements, maxDepth)) { return(false); } Debug.Assert(defaultBlock.HasFlag(InstructionFlags.EndPointUnreachable)); // ensure the default case dominator tree has no exits (branches to other cases) var cfg = new ControlFlowGraph(switchContainer, context.CancellationToken); var defaultNode = cfg.GetNode(defaultBlock); var defaultTree = TreeTraversal.PreOrder(defaultNode, n => n.DominatorTreeChildren).ToList(); if (defaultTree.SelectMany(n => n.Successors).Any(n => !defaultNode.Dominates(n))) { return(false); } if (defaultTree.Count > 1 && !(parentBlock.Parent is BlockContainer)) { return(false); } context.Step("Extract default case of switch", switchContainer); // replace all break; statements with the exitInst var leaveInstructions = switchContainer.Descendants.Where(inst => inst.MatchLeave(switchContainer)); foreach (var leaveInst in leaveInstructions.ToArray()) { leaveInst.ReplaceWith(exitInst.Clone()); } // replace the default section branch with a break; defaultSection.Body.ReplaceWith(new Leave(switchContainer)); // remove all default blocks from the switch container var defaultBlocks = defaultTree.Select(c => (Block)c.UserData).ToList(); foreach (var block in defaultBlocks) { switchContainer.Blocks.Remove(block); } // replace the parent block exit with the default case instructions if (parentBlock.Instructions.Last() == exitInst) { parentBlock.Instructions.RemoveLast(); } // Note: even though we don't check that the switchContainer is near the end of the block, // we know this must be the case because we know "exitInst" is a leave/branch and directly // follows the switchContainer. Debug.Assert(parentBlock.Instructions.Last() == switchContainer); parentBlock.Instructions.AddRange(defaultBlock.Instructions); // add any additional blocks from the default case to the parent container Debug.Assert(defaultBlocks[0] == defaultBlock); if (defaultBlocks.Count > 1) { var parentContainer = (BlockContainer)parentBlock.Parent; int insertAt = parentContainer.Blocks.IndexOf(parentBlock) + 1; foreach (var block in defaultBlocks.Skip(1)) { parentContainer.Blocks.Insert(insertAt++, block); } } return(true); }
/// <summary> /// Examines a CFG and removes the stack manipulating instructions by introducing /// some explicit variables for stack locations. After this transformation, no more /// Pop, Dup etc. /// </summary> /// <param name="cfg">Control Flow Graph that is modified by the transformation. /// This argument WILL be mutated.</param> /// <returns>A map that assigns to each block from <c>cfg</c> the stack depth at its /// beginning. Useful as a pseudo-liveness information.</returns> public static int[] Process(ControlFlowGraph cfg) { StackRemovalTransformation sd = new StackRemovalTransformation(cfg); StackRemovalVisitor srv = new StackRemovalVisitor(); // should be in order. foreach (CfgBlock block in cfg.PreOrder) { int depth = sd.InitialDepthOfBlock(block, cfg); if (depth < 0) { continue; } // set block starting depth srv.depth = depth; StatementList stats = block.Statements; for(int i = 0, n = stats.Count; i < n; i++) { stats[i] = (Statement) srv.Visit(stats[i]); if (cfg.GenericsUse == null) { cfg.GenericsUse = srv.GenericsUse; } if (cfg.PointerUse == null) { cfg.PointerUse = srv.PointerUse; } if (srv.SawMissingInfo) { cfg.HasMissingInfo = true; } } // push final depth onto successors. foreach (CfgBlock succ in cfg.NormalSucc(block)) { sd.PushDepth(succ, srv.depth); } } // finalize stack depth info on each block foreach (CfgBlock block in cfg.Blocks()) { int depth = sd.block2depth[block.Index]; // cache depth on block block.stackDepth = depth; if (depth < 0) { // unreachable // set statementlist to null in case some backward analysis or other code gets to it if (block.Statements.Count > 0) { block.Statements = new StatementList(0); } } } return sd.block2depth; }
private DataFlowAnalyzer(ControlFlowGraph cfg, ISymbol owningSymbol) { _analysisData = FlowGraphAnalysisData.Create(cfg, owningSymbol, AnalyzeLocalFunctionOrLambdaInvocation); }
protected override void Run(ControlFlowGraph cfg, IDataFlowState startState) { base.Run(cfg, startState); }
protected override void PreProcess() { _cfg = Compilation.CreateCFG(InInstructions); }