public static IEnumerable <(VariableName, uint)> FindReadCounts(this IBasicBlock block) { var r = new FindReadVariables(); r.Visit(block); return(r.Counts.Select(a => (a.Key, a.Value))); }
private void AddTryStart(IRTransformer tr) { var tryStartInstrs = new List <IRInstruction>(); for (var i = 0; i < thisScopes.Length; i++) { var scope = thisScopes[i]; if (scope.Type != ScopeType.Try) { continue; } if (scope.GetBasicBlocks().First() != tr.Block) { continue; } // Search for handler/filter IBasicBlock handler = null, filter = null; SearchForHandlers(tr.RootScope, scope.ExceptionHandler, ref handler, ref filter); Debug.Assert(handler != null && (scope.ExceptionHandler.HandlerType != ExceptionHandlerType.Filter || filter != null)); // Add instructions tryStartInstrs.Add(new IRInstruction(IROpCode.PUSH, new IRBlockTarget(handler))); IIROperand tryOperand = null; int ehType; if (scope.ExceptionHandler.HandlerType == ExceptionHandlerType.Catch) { tryOperand = IRConstant.FromI4((int)tr.VM.Data.GetId(scope.ExceptionHandler.CatchType)); ehType = tr.VM.Runtime.RTFlags.EH_CATCH; } else if (scope.ExceptionHandler.HandlerType == ExceptionHandlerType.Filter) { tryOperand = new IRBlockTarget(filter); ehType = tr.VM.Runtime.RTFlags.EH_FILTER; } else if (scope.ExceptionHandler.HandlerType == ExceptionHandlerType.Fault) { ehType = tr.VM.Runtime.RTFlags.EH_FAULT; } else if (scope.ExceptionHandler.HandlerType == ExceptionHandlerType.Finally) { ehType = tr.VM.Runtime.RTFlags.EH_FINALLY; } else { throw new InvalidProgramException(); } tryStartInstrs.Add(new IRInstruction(IROpCode.TRY, IRConstant.FromI4(ehType), tryOperand) { Annotation = new EHInfo(scope.ExceptionHandler) }); } tr.Instructions.InsertRange(0, tryStartInstrs); }
public IEdge CreateEdge(IBasicBlock start, IBasicBlock end, EdgeType type) { var e = new Edge(start, end, type); _vertexLookup[start.ID].AddOutgoing(e); _vertexLookup[end.ID].AddIncoming(e); _edges.Add(e); return(e); }
static void VisitSuccessorsCore(IBasicBlock basicBlock, HashSet <IBlock> isVisiteds) { VisitScope(basicBlock, isVisiteds); foreach (var successor in basicBlock.Successors.Keys) { if (!isVisiteds.Add(successor)) { continue; } VisitSuccessorsCore(successor, isVisiteds); } }
[NotNull] public static IModel BuildSAT([NotNull] this IBasicBlock block, [NotNull] ITypeAssignments types) { var ctx = new Context(); var solver = ctx.MkSolver(); var model = new Model(ctx, solver); foreach (var stmt in block.Statements) { Assert(model, types, stmt); } return(model); }
private void SearchForHandlers(ScopeBlock scope, ExceptionHandler eh, ref IBasicBlock handler, ref IBasicBlock filter) { if (scope.ExceptionHandler == eh) { if (scope.Type == ScopeType.Handler) { handler = scope.GetBasicBlocks().First(); } else if (scope.Type == ScopeType.Filter) { filter = scope.GetBasicBlocks().First(); } } foreach (var child in scope.Children) { SearchForHandlers(child, eh, ref handler, ref filter); } }
[NotNull] private static Line ConvertLine([NotNull] IBasicBlock entry) { var statements = new List <BaseStatement>(); var e = entry.Outgoing.Single(); if (e.Type != EdgeType.Continue) { throw new InvalidOperationException("LineStart block has an invalid edge"); } if (e.End.LineNumber == e.Start.LineNumber) { RecursiveConvertBlock(e.End, statements); } return(new Line(new StatementList(statements))); }
private static bool SearchBlockInternal(ScopeBlock scope, IBasicBlock target, Stack <ScopeBlock> scopeStack) { if (scope.Content.Count > 0) { if (scope.Content.Contains(target)) { scopeStack.Push(scope); return(true); } return(false); } scopeStack.Push(scope); foreach (var child in scope.Children) { if (SearchBlockInternal(child, target, scopeStack)) { return(true); } } scopeStack.Pop(); return(false); }
public bool Equals(IBasicBlock other) { if (ReferenceEquals(null, other)) { return(false); } if (ReferenceEquals(this, other)) { return(true); } if (!ID.Equals(other.ID)) { return(false); } if (_statements.Count != other.Statements.Count()) { return(false); } return(_statements.Zip(other.Statements, (a, b) => a.Equals(b)).All(a => a)); }
private void VisitInstr(IRInstrList instrs, IRInstruction instr, ref int index, IRTransformer tr) { if (instr.OpCode != IROpCode.__LEAVE) { return; } var targetScopes = tr.RootScope.SearchBlock(((IRBlockTarget)instr.Operand1).Target); var escapeTarget = FindCommonAncestor(thisScopes, targetScopes); var leaveInstrs = new List <IRInstruction>(); for (var i = thisScopes.Length - 1; i >= 0; i--) { if (thisScopes[i] == escapeTarget) { break; } if (thisScopes[i].Type != ScopeType.Try) { continue; } IBasicBlock handler = null, filter = null; SearchForHandlers(tr.RootScope, thisScopes[i].ExceptionHandler, ref handler, ref filter); if (handler == null) { throw new InvalidProgramException(); } leaveInstrs.Add(new IRInstruction(IROpCode.LEAVE, new IRBlockTarget(handler)) { Annotation = new EHInfo(thisScopes[i].ExceptionHandler) }); } instr.OpCode = IROpCode.JMP; leaveInstrs.Add(instr); instrs.Replace(index, leaveInstrs); }
/// <summary> /// Find the first instrucion index that is not affected by the junk insertion in the new block. /// In other words: it Finds the first instruction in the new block which is identical to instruction /// in the original basic block. the identical instruction start an identical sequence of instructions /// untill the end of the two blocks. /// </summary> /// <param name="newBasicBlockBytes">new basic block bytes</param> /// <param name="basicBlock">original basic block</param> /// <param name="disassemblerFactory">diassembler factory</param> /// <returns>the first index of unaffected instruction in the original basic block, or not o value otherwise</returns> private uint?CompareDisassembleToOriginal(byte[] newBasicBlockBytes, IBasicBlock basicBlock, IDisassemblerFactory disassemblerFactory) { //disassemble new bytes after junk have been inserted var newAssemblyInstructions = new List <IAssemblyInstructionForTransformation>(); IDisassembler disasm = disassemblerFactory.Create(newBasicBlockBytes); foreach (var instruction in disasm.Disassemble()) { newAssemblyInstructions.Add(instruction); } //not enought instruction have been decoded right in this block! if (newAssemblyInstructions.Count <= 1) { return(null); } //compare to original basic block instructions //start from index 1 because first instruction is the inserted junk... for (int i = 1; i < newAssemblyInstructions.Count(); i++) { for (int j = 0; j < basicBlock.AssemblyInstructions.Count; j++) { //compare instruction until the end if they are equal if (newAssemblyInstructions[i].BytesEquals(basicBlock.AssemblyInstructions[j])) { if (instructionAreIdenticalUntilTheEnd(newAssemblyInstructions, i + 1, basicBlock.AssemblyInstructions, j + 1)) { return((uint?)j); } } } } return(null); }
static IReadOnlyDictionary <IBasicBlock, uint> Visit(IBasicBlock block, uint depth, Dictionary <IBasicBlock, uint> depths) { // If we've already been to this block by a shorter route early exit if (depths.TryGetValue(block, out var prevDepth)) { if (prevDepth < depth) { return(depths); } } // Discovered this block depths[block] = depth; // Get edges we care about var outs = block.Outgoing.Where(e => (e.Type == EdgeType.Continue || e.Type == EdgeType.ConditionalTrue || e.Type == EdgeType.ConditionalFalse) && e.Start.LineNumber == e.End.LineNumber); foreach (var @out in outs) { Visit(@out.End, depth + 1, depths); } return(depths); }
public DataFlowGraph(IBasicBlock block, ISingleStaticAssignmentTable ssa) : this(ssa) { // Convert statements foreach (var stmt in block.Statements) { if (stmt is Assignment ass) { AddAssignment(ass.Left, Add(ass.Right)); } else if (stmt is Conditional con) { AddConditional(Add(con.Condition)); } else if (stmt is Goto @goto) { AddGoto(Add(@goto.Destination)); } else { throw new NotSupportedException(stmt.GetType().Name); } } }
[NotNull] public static IDataFlowGraph DataFlowGraph([NotNull] this IBasicBlock block, [NotNull] ISingleStaticAssignmentTable ssa) { return(new DataFlowGraph(block, ssa)); }
public ILBlockTarget(IBasicBlock target) { Target = target; }
public ICode Transform(ICode code, TryTransformInstructionDelegate transformInstructionDelegate, Func <ICodeInMemoryLayout> codeInLayoutFactoryDelegate = null) { var newInstructionsList = new List <IAssemblyInstructionForTransformation>(); var newFunctionsList = new List <IFunction>(); var instructionListIterator = code.AssemblyInstructions.GetEnumerator(); var lastInstructionInLastBlock = code.Functions.Last().BasicBlocks.Last().AssemblyInstructions.Last(); IAssemblyInstructionForTransformation previousInstruction = null; bool afterInstructionOfLastBlock = false; //move to the first instruction instructionListIterator.MoveNext(); //iterate through all functions foreach (var function in code.Functions) { var basicBlockList = new List <IBasicBlock>(); //iterate through all basic block foreach (var basicBlock in function.BasicBlocks) { var instructionsListOfBlock = new List <IAssemblyInstructionForTransformation>(); foreach (var instructionInBasicBlock in basicBlock.AssemblyInstructions) { bool isInstructionInBasicBlock; bool done = false; //transform instructions from instruction list. //this loop transform: //1. instructions before the basic block which are left to process //2. instructions inside a basic block //3. instructions after the last basic block while (!done) { isInstructionInBasicBlock = instructionListIterator.Current == instructionInBasicBlock; IAssemblyInstructionForTransformation instructionToTransform = instructionListIterator.Current; //perfom the transformation of the instruction List <IAssemblyInstructionForTransformation> transformedInstructionList; var wasTransformed = transformInstructionDelegate(instructionToTransform, isInstructionInBasicBlock ? basicBlock : null, isInstructionInBasicBlock ? function : null, out transformedInstructionList); if (wasTransformed) { if (transformedInstructionList.Count == 0) { throw new ApplicationException("transformation should return at least one instruction"); } if (isInstructionInBasicBlock) { instructionsListOfBlock.AddRange(transformedInstructionList); } newInstructionsList.AddRange(transformedInstructionList); if (previousInstruction != null) { transformedInstructionList[0].PreviousInstruction = previousInstruction; previousInstruction.NextInstruction = transformedInstructionList[0]; } if (transformedInstructionList.Count > 1) { for (int i = 1; i < transformedInstructionList.Count; i++) { transformedInstructionList[i].PreviousInstruction = transformedInstructionList[i - 1]; transformedInstructionList[i - 1].NextInstruction = transformedInstructionList[i]; } } previousInstruction = transformedInstructionList.Last(); } else { if (isInstructionInBasicBlock) { instructionsListOfBlock.Add(instructionToTransform); } newInstructionsList.Add(instructionToTransform); if (previousInstruction != null) { instructionToTransform.PreviousInstruction = previousInstruction; previousInstruction.NextInstruction = instructionToTransform; } previousInstruction = instructionToTransform; } //check weather this is the last instruction in the last basic block if (isInstructionInBasicBlock && !afterInstructionOfLastBlock) { //The transformed instruction is now in the end of program //after the last basic block instruction afterInstructionOfLastBlock = (instructionToTransform == lastInstructionInLastBlock); } instructionListIterator.MoveNext(); //stop transforming intructions in loop when all instruction in scope are processed done = (isInstructionInBasicBlock || instructionListIterator.Current == null); //keep transforming after the last basic block instruction to the end of the program if (afterInstructionOfLastBlock && instructionListIterator.Current != null) { done = false; } } } IBasicBlock newBasicBlock = m_basicBlockFactory.Create(instructionsListOfBlock); basicBlockList.Add(newBasicBlock); } var newFunction = m_functionFactory.Create(basicBlockList.First().AssemblyInstructions.First(), basicBlockList.Last().AssemblyInstructions.Last(), basicBlockList); newFunctionsList.Add(newFunction); } //if there is a factory to create a new code in memory layout structure than use it, otherwise use //the original code layout in memrory instance ICodeInMemoryLayout codeInMemoryLayout = codeInLayoutFactoryDelegate == null ? code.CodeInMemoryLayout:codeInLayoutFactoryDelegate(); //return m_codeFactory.Create(newInstructionsList, newFunctionsList,codeInMemoryLayout); var newcode = m_codeFactory.Create(newInstructionsList, newFunctionsList, codeInMemoryLayout); ValidateNewCode(newcode); return(newcode); }
protected override void FormatBasicBlockCore(IBasicBlock basicBlock) { FormatBasicBlockImpl((BasicBlock)basicBlock); }
static bool IsDirectBranch(IBasicBlock bb) { return(bb.FlowType == FlowControl.Branch && (bb.FlowAnnotation & (FlowControl.Leave | FlowControl.Indirect)) == 0); }
public ILBlockTarget(IBasicBlock target) => this.Target = target;
int IDictionary <IBasicBlock, int> .this[IBasicBlock key] { get => this[(TBasicBlock)key];
private void AddFallthrough(IMutableControlFlowGraph cfg, IBasicBlock source, int currentLineNumber, EdgeType type = EdgeType.Continue) { cfg.CreateEdge(source, GetLineEntryBlock(cfg, currentLineNumber == _maxLines ? 1 : currentLineNumber + 1), type); }
private bool TryGenerateJunkInstruction(IBasicBlock basicBlock, IJunkBytesProvider junkBytesProvider, IStatistics statistics, out IAssemblyInstructionForTransformation junkInstruction) { junkInstruction = null; bool retVal = false; //get junk bytes byte[] junkBytes = junkBytesProvider.GetJunkBytes(); if (junkBytes == null) { throw new NullReferenceException(nameof(junkBytes)); } //get basic block bytes byte[] basicBlockBytes = basicBlock.GetAllBytes(); //the size of the junk we try to insert uint junkBytesSize = (uint)junkBytes.Count(); //the inde of the most far insruction that has been syncronized uint mostFarSyncInstructionIdx = 0; //the partial instruction that causes the synchronization to be far as possible uint bestPartialInstructionSize = 0; //check what sub array of the inserted junk causes the most of confusion //so instruction are disassembled not correctly as far as possible while (junkBytesSize > 0) { uint sizeOfNewBytesArray = basicBlock.NumberOfBytes + junkBytesSize; byte[] newBasicBlockBytes = new byte[sizeOfNewBytesArray]; //copy junk bytes and then basic block bytes Array.Copy(junkBytes, newBasicBlockBytes, junkBytesSize); basicBlockBytes.CopyTo(newBasicBlockBytes, junkBytesSize); //the index of first identical disassembled instruction to original uint?indexOfFirstIdenticalInstruction = CompareDisassembleToOriginal(newBasicBlockBytes, basicBlock, m_disassemblerFactory); //in case that there is no even one instruction that synchronizes, so try another sequence //because the parsing error can not proceed to the next block if (!indexOfFirstIdenticalInstruction.HasValue) { junkBytesSize--; continue; } if (indexOfFirstIdenticalInstruction.Value > mostFarSyncInstructionIdx) { mostFarSyncInstructionIdx = indexOfFirstIdenticalInstruction.Value; bestPartialInstructionSize = junkBytesSize; } junkBytesSize--; } //update basic block with the instruction that causes the synchronization to be as far as //possible if (mostFarSyncInstructionIdx > 0) { byte[] junkBytesSelected = new byte[bestPartialInstructionSize]; for (int i = 0; i < bestPartialInstructionSize; i++) { junkBytesSelected[i] = junkBytes[i]; } var disasm = m_disassemblerFactory.Create(junkBytesSelected); junkInstruction = disasm.Disassemble().First(); junkInstruction.IsNew = true; statistics.IncrementMissinterpretedInstructions(mostFarSyncInstructionIdx); statistics.IncrementJunkInstructions(1, (uint)junkInstruction.Length); retVal = true; } return(retVal); }
public Edge(IBasicBlock start, IBasicBlock end, EdgeType type) { Start = start; End = end; Type = type; }
protected override string FormatBlockId(IBasicBlock basicBlock) { return($"BLK_{((BasicBlock)basicBlock).OriginalOffset:X4}"); }
public IReadOnlyList <IBasicBlock> Parse(IAssemblyInstructionForTransformation firstInstruction, IAssemblyInstructionForTransformation lastInstruction, Dictionary <ulong, ulong> jumpTargetAddresses) { if (firstInstruction == null) { throw new ArgumentNullException(nameof(firstInstruction)); } if (lastInstruction == null) { throw new ArgumentNullException(nameof(lastInstruction)); } if (jumpTargetAddresses == null) { throw new ArgumentNullException(nameof(jumpTargetAddresses)); } if (firstInstruction.Offset >= lastInstruction.Offset) { throw new ArgumentException("first argument address should be less then last argument address", "firstInstruction"); } List <IBasicBlock> basicBlocks = new List <IBasicBlock>(); var currrentInstruction = firstInstruction; while (currrentInstruction.Offset <= lastInstruction.Offset) { //find the basic block epilog var basicBlockEpilog = BasicBlockEpilogParser.Parse(currrentInstruction, lastInstruction.Offset, jumpTargetAddresses); //no epilog was found, for example because the code examined is not a function or ends when the whole code section ends... if (basicBlockEpilog == null) { break; } //initialize the assembly instructions of the current basic block being parsed. var assemblyInstructions = new List <IAssemblyInstructionForTransformation>() { currrentInstruction }; //Add all instruction in between the current and epilog instruction of the basic block if (currrentInstruction != basicBlockEpilog) { currrentInstruction = currrentInstruction.NextInstruction; while (currrentInstruction != null && //may not be possible to happen currrentInstruction != basicBlockEpilog) { assemblyInstructions.Add(currrentInstruction); currrentInstruction = currrentInstruction.NextInstruction; } //add epilog instruction assemblyInstructions.Add(basicBlockEpilog); } IBasicBlock basicBlock = BasicBlockFactory.Create(assemblyInstructions); basicBlocks.Add(basicBlock); currrentInstruction = currrentInstruction.NextInstruction; } return(basicBlocks); }
/// <summary /> protected virtual string FormatSuccessors(IBasicBlock basicBlock) { return(string.Join(", ", basicBlock.Successors.Keys.Select(t => FormatBlockId(t)))); }
[CanBeNull] private static IBasicBlock FindCommonSubsequentBlock([NotNull] IBasicBlock a, [NotNull] IBasicBlock b) { IReadOnlyDictionary <IBasicBlock, uint> Visit(IBasicBlock block, uint depth, Dictionary <IBasicBlock, uint> depths) { // If we've already been to this block by a shorter route early exit if (depths.TryGetValue(block, out var prevDepth)) { if (prevDepth < depth) { return(depths); } } // Discovered this block depths[block] = depth; // Get edges we care about var outs = block.Outgoing.Where(e => (e.Type == EdgeType.Continue || e.Type == EdgeType.ConditionalTrue || e.Type == EdgeType.ConditionalFalse) && e.Start.LineNumber == e.End.LineNumber); foreach (var @out in outs) { Visit(@out.End, depth + 1, depths); } return(depths); } var ad = Visit(a, 0, new Dictionary <IBasicBlock, uint>()); var bd = Visit(b, 0, new Dictionary <IBasicBlock, uint>()); return(ad.Where(x => bd.ContainsKey(x.Key)).OrderBy(x => x.Value).FirstOrDefault().Key); }
[NotNull] public static StatementList Visit([NotNull] this BaseTreeVisitor visitor, [NotNull] IBasicBlock block) { var result = visitor.Visit(new Program(new Line[] { new Line(new StatementList(block.Statements)) })); return(result.Lines.Single().Statements); }
/// <summary> /// Convert a basic block, recursively convert linked blocks on the same line which are not the stop block /// </summary> /// <param name="block"></param> /// <param name="output"></param> /// <param name="stop"></param> private static void RecursiveConvertBlock([NotNull] IBasicBlock block, [NotNull] List <BaseStatement> output, [CanBeNull] IBasicBlock stop = null) { if (stop != null && stop.ID.Equals(block.ID)) { return; } // Copy statements from this block into output output.AddRange(block.Statements); // if a block is empty there's nothing more to do if (!block.Statements.Any()) { return; } // If we've jumped away there's nothing more to convert on this line if (block.Statements.Last() is Goto) { return; } // Serialize if statement if (block.Statements.Last() is Conditional con) { // Remove `Conditional` node, we'll replace with an `if` output.RemoveAt(output.Count - 1); // Find conditional edges leaving this block var trueEdge = block.Outgoing.Single(a => a.Type == EdgeType.ConditionalTrue); var falseEdge = block.Outgoing.Single(a => a.Type == EdgeType.ConditionalFalse); // There are four possible cases: // - True/False branches both eventually pass on control flow to a common block (continueWith is common block) // - True jumps away, False is effectively the rest of the line (continueWith is false branch) // - False jumps away, True is effectively the rest of the line (continueWith is true branch) // - Both jump away, this is the end of the line (continueWith is null) // Try to find the first common block on this line var common = FindCommonSubsequentBlock(trueEdge.End, falseEdge.End); if (common != null) { // Serialize both branches up to common block var trueStmts = new List <BaseStatement>(); RecursiveConvertBlock(trueEdge.End, trueStmts, common); var falseStmts = new List <BaseStatement>(); RecursiveConvertBlock(falseEdge.End, falseStmts, common); output.Add(new If(con.Condition, new StatementList(trueStmts), new StatementList(falseStmts))); } else { var trueStmts = new List <BaseStatement>(); RecursiveConvertBlock(trueEdge.End, trueStmts); var falseStmts = new List <BaseStatement>(); RecursiveConvertBlock(falseEdge.End, falseStmts); output.Add(new If(con.Condition, new StatementList(trueStmts), new StatementList(falseStmts))); return; } // Continue on with rest of the line RecursiveConvertBlock(common, output, stop); } // Try to continue to the next block var e = block.Outgoing.SingleOrDefault(a => a.Type == EdgeType.Continue); if (e != null && e.Type == EdgeType.Continue && e.End.LineNumber == block.LineNumber && e.End != stop) { RecursiveConvertBlock(e.End, output, stop); } }
private static IBasicBlock?FindCommonSubsequentBlock(IBasicBlock a, IBasicBlock b) {