protected static BasicBlock ExtractAsBasicBlock(BasicBlock b, int i, int j) { List<IStatement> statements = b.Statements; BasicBlock result = new BasicBlock(0); if (b.LocalVariables != null) result.LocalVariables = new List<ILocalDefinition>(b.LocalVariables); while (i < j) { var s = statements[i++]; MoveTempIfNecessary(b, result, s); result.Statements.Add(s); } return result; }
protected static BasicBlock GetBasicBlockStartingAt(BasicBlock bb, uint offset) { while (bb.StartOffset < offset && bb.Statements.Count > 0) { BasicBlock bbb = bb.Statements[bb.Statements.Count-1] as BasicBlock; if (bbb == null) return new BasicBlock(offset); if (bbb.StartOffset == offset) { bb.Statements.RemoveAt(bb.Statements.Count-1); return bbb; } bb = bbb; } return bb; }
internal void Traverse(SourceMethodBody body, BasicBlock rootBlock) { this.Traverse(rootBlock); //Now add declarations for any locals declared only on the body (for example temporary variables introduced by Unstacker). List<IStatement> prelude = new List<IStatement>(); var localsAndTemps = body.localVariablesAndTemporaries; this.AddDeclarationsWithInitialValues(localsAndTemps, rootBlock); foreach (var localDef in localsAndTemps) { if (this.declaredLocals.ContainsKey(localDef)) continue; LocalDeclarationStatement localDecl = new LocalDeclarationStatement(); localDecl.LocalVariable = localDef; prelude.Add(localDecl); } if (prelude.Count > 0) rootBlock.Statements.InsertRange(0, prelude); //TODO: use pdb info to insert them in the same order they appear in the source }
private void Flatten(BasicBlock blockStatement, List<IStatement> flatListOfStatements) { foreach (IStatement statement in blockStatement.Statements){ BasicBlock/*?*/ nestedBlock = statement as BasicBlock; if (nestedBlock != null) { if (nestedBlock.LocalVariables == null || nestedBlock.LocalVariables.Count == 0 || nestedBlock.Statements.Count == 0 || (nestedBlock.Statements.Count == 1 && nestedBlock.Statements[0] is BasicBlock)) this.Flatten(nestedBlock, flatListOfStatements); else { this.Traverse(nestedBlock); flatListOfStatements.Add(nestedBlock); } } else { this.Traverse(statement); flatListOfStatements.Add(statement); } } }
protected static BasicBlock GetBasicBlockUpto(BasicBlock b, uint endOffset) { BasicBlock result = new BasicBlock(b.StartOffset); if (b.LocalVariables != null) result.LocalVariables = new List<ILocalDefinition>(b.LocalVariables); result.EndOffset = endOffset; int n = b.Statements.Count; for (int i = 0; i < n-1; i++) { var s = b.Statements[i]; MoveTempIfNecessary(b, result, s); result.Statements.Add(b.Statements[i]); } if (n > 0) { b.Statements.RemoveRange(0, n-1); BasicBlock bb = (BasicBlock)b.Statements[0]; if (bb.StartOffset < endOffset) result.Statements.Add(GetBasicBlockUpto(bb, endOffset)); } return result; }
// For the first assignment to a local variable in a block before a control statement is hit, // if the local variable is not mentioned previously, we turn this assignment into a local declaration. private void AddDeclarationsWithInitialValues(IEnumerable <ILocalDefinition> localVariables, BasicBlock block) { List <ILocalDefinition> topLevelLocals = new List <ILocalDefinition>(localVariables); List <ILocalDefinition> localsMet = new List <ILocalDefinition>(); for (int i = 0; i < block.Statements.Count; i++) { if (topLevelLocals.Count == 0) { break; } IExpressionStatement expressionStatement = block.Statements[i] as IExpressionStatement; if (expressionStatement != null) { IAssignment assignment = expressionStatement.Expression as IAssignment; if (assignment != null) { ILocalDefinition localDef = assignment.Target.Definition as ILocalDefinition; if (localDef != null && topLevelLocals.Contains(localDef) && !localsMet.Contains(localDef) && !this.declaredLocals.ContainsKey(localDef)) { LocalDeclarationStatement localDecl = new LocalDeclarationStatement() { LocalVariable = localDef, InitialValue = assignment.Source, Locations = new List <ILocation>(expressionStatement.Locations), }; this.declaredLocals.Add(localDef, true); block.Statements[i] = localDecl; topLevelLocals.Remove(localDef); localsMet.Add(localDef); } } } LocalFinder finder = new LocalFinder(); finder.Traverse(block.Statements[i]); foreach (ILocalDefinition local in finder.FoundLocals) { if (!localsMet.Contains(local)) { localsMet.Add(local); } } //Once we see a statement that can transfer control somewhere else, we //no longer know that any subsequent assignment dominates all references //and hence cannot postpone adding the declaration until we can unify it with the assignment. IGotoStatement gotoStatement = block.Statements[i] as IGotoStatement; if (gotoStatement != null) { break; } IConditionalStatement conditionalStatement = block.Statements[i] as IConditionalStatement; if (conditionalStatement != null) { break; } ISwitchStatement switchStatement = block.Statements[i] as ISwitchStatement; if (switchStatement != null) { break; } IForEachStatement foreachStatement = block.Statements[i] as IForEachStatement; if (foreachStatement != null) { break; } IForStatement forStatement = block.Statements[i] as IForStatement; if (forStatement != null) { break; } ITryCatchFinallyStatement tryStatement = block.Statements[i] as ITryCatchFinallyStatement; if (tryStatement != null) { break; } } }
private void Traverse(BasicBlock b) { this.blockLocalVariables = b.LocalVariables; for (int i = 0; i < b.Statements.Count; i++) { this.DeleteGotoNextStatement(b.Statements, i); this.ReplaceLocalArrayInitializerPattern(b.Statements, i); this.ReplaceShortCircuitPattern(b.Statements, i); this.ReplaceShortCircuitPattern2(b.Statements, i); this.ReplacePushPopPattern(b.Statements, i); } if (this.blockLocalVariables != b.LocalVariables) b.LocalVariables = this.blockLocalVariables; }
private void TurnOperandStackIntoPushStatements(BasicBlock currentBlock) { int insertPoint = currentBlock.Statements.Count; while (this.operandStack.Count > 0) { Expression operand = this.PopOperandStack(); MethodCall/*?*/ call = operand as MethodCall; if (call != null && call.MethodToCall.Type.TypeCode == PrimitiveTypeCode.Void) { ExpressionStatement expressionStatement = new ExpressionStatement(); expressionStatement.Expression = operand; currentBlock.Statements.Insert(insertPoint, expressionStatement); } else { PushStatement push = new PushStatement(); push.ValueToPush = operand; currentBlock.Statements.Insert(insertPoint, push); } } }
private static IExpression ExtractFilterCondition(BasicBlock handlerBlock) { int endFilterIndex = -1; IExpression result = CodeDummy.Expression; for (int i = 0; i < handlerBlock.Statements.Count; i++) { var endFilter = handlerBlock.Statements[i] as EndFilter; if (endFilter != null) { result = endFilter.FilterResult; endFilterIndex = i; break; } } if (endFilterIndex < 0) return result; if (endFilterIndex == 0) { handlerBlock.Statements.RemoveAt(0); return result; } var blockExpression = new BlockExpression(); blockExpression.BlockStatement = ExtractAsBasicBlock(handlerBlock, 0, endFilterIndex); blockExpression.Expression = result; blockExpression.Type = result.Type; handlerBlock.Statements.RemoveRange(0, endFilterIndex+1); return blockExpression; }
private void FindLastUsesOfLocals(BasicBlock<Instruction> bb) { Contract.Requires(bb != null); for (int i = 0, n = bb.Instructions.Count; i < n; i++) { Contract.Assume(i < bb.Instructions.Count); var instruction = bb.Instructions[i]; switch (instruction.Operation.OperationCode) { case OperationCode.Ldloc: case OperationCode.Ldloc_0: case OperationCode.Ldloc_1: case OperationCode.Ldloc_2: case OperationCode.Ldloc_3: case OperationCode.Ldloc_S: case OperationCode.Ldloca: case OperationCode.Ldloca_S: var local = (ILocalDefinition)instruction.Operation.Value; if (this.NextReferenceIsAssignment(local, bb, i+1, new SetOfObjects())) this.instructionsThatMakeALastUseOfALocalVersion.Add(instruction); break; } } }
/// <summary> /// Parse instructions and put them into an expression tree until an assignment, void call, branch target, or branch is encountered. /// Returns true if the parsed statement is last of the current basic block. This happens when the next statement is a branch /// target, or if the parsed statement could transfers control to anything but the following statement. /// </summary> private void ParseInstruction(BasicBlock currentBlock) { Statement/*?*/ statement = null; Expression/*?*/ expression = null; IOperation currentOperation = this.operationEnumerator.Current; OperationCode currentOpcode = currentOperation.OperationCode; if (this.host.PreserveILLocations) { if (this.lastLocation == null) this.lastLocation = currentOperation.Location; } else { if (this.sourceLocationProvider != null && this.lastSourceLocation == null) { foreach (var sourceLocation in this.sourceLocationProvider.GetPrimarySourceLocationsFor(currentOperation.Location)) { if (sourceLocation.StartLine != 0x00feefee) { this.lastSourceLocation = sourceLocation; break; } } } } switch (currentOpcode) { case OperationCode.Add: case OperationCode.Add_Ovf: case OperationCode.Add_Ovf_Un: case OperationCode.And: case OperationCode.Ceq: case OperationCode.Cgt: case OperationCode.Cgt_Un: case OperationCode.Clt: case OperationCode.Clt_Un: case OperationCode.Div: case OperationCode.Div_Un: case OperationCode.Mul: case OperationCode.Mul_Ovf: case OperationCode.Mul_Ovf_Un: case OperationCode.Or: case OperationCode.Rem: case OperationCode.Rem_Un: case OperationCode.Shl: case OperationCode.Shr: case OperationCode.Shr_Un: case OperationCode.Sub: case OperationCode.Sub_Ovf: case OperationCode.Sub_Ovf_Un: case OperationCode.Xor: expression = this.ParseBinaryOperation(currentOpcode); break; case OperationCode.Arglist: expression = new RuntimeArgumentHandleExpression(); break; case OperationCode.Array_Addr: case OperationCode.Ldelema: expression = this.ParseArrayElementAddres(currentOperation); break; case OperationCode.Array_Create: case OperationCode.Array_Create_WithLowerBound: case OperationCode.Newarr: expression = this.ParseArrayCreate(currentOperation); break; case OperationCode.Array_Get: case OperationCode.Ldelem: case OperationCode.Ldelem_I: case OperationCode.Ldelem_I1: case OperationCode.Ldelem_I2: case OperationCode.Ldelem_I4: case OperationCode.Ldelem_I8: case OperationCode.Ldelem_R4: case OperationCode.Ldelem_R8: case OperationCode.Ldelem_Ref: case OperationCode.Ldelem_U1: case OperationCode.Ldelem_U2: case OperationCode.Ldelem_U4: expression = this.ParseArrayIndexer(currentOperation); break; case OperationCode.Array_Set: statement = this.ParseArraySet(currentOperation); break; case OperationCode.Beq: case OperationCode.Beq_S: case OperationCode.Bge: case OperationCode.Bge_S: case OperationCode.Bge_Un: case OperationCode.Bge_Un_S: case OperationCode.Bgt: case OperationCode.Bgt_S: case OperationCode.Bgt_Un: case OperationCode.Bgt_Un_S: case OperationCode.Ble: case OperationCode.Ble_S: case OperationCode.Ble_Un: case OperationCode.Ble_Un_S: case OperationCode.Blt: case OperationCode.Blt_S: case OperationCode.Blt_Un: case OperationCode.Blt_Un_S: case OperationCode.Bne_Un: case OperationCode.Bne_Un_S: statement = this.ParseBinaryConditionalBranch(currentOperation); break; case OperationCode.Box: expression = this.ParseConversion(currentOperation); break; case OperationCode.Br: case OperationCode.Br_S: case OperationCode.Leave: case OperationCode.Leave_S: statement = this.ParseUnconditionalBranch(currentOperation); break; case OperationCode.Break: statement = new DebuggerBreakStatement(); break; case OperationCode.Brfalse: case OperationCode.Brfalse_S: case OperationCode.Brtrue: case OperationCode.Brtrue_S: statement = this.ParseUnaryConditionalBranch(currentOperation); break; case OperationCode.Call: case OperationCode.Callvirt: MethodCall call = this.ParseCall(currentOperation); if (call.MethodToCall.Type.TypeCode == PrimitiveTypeCode.Void) { call.Locations.Add(currentOperation.Location); // turning it into a statement prevents the location from being attached to the expresssion ExpressionStatement es = new ExpressionStatement(); es.Expression = call; statement = es; } else expression = call; break; case OperationCode.Calli: expression = this.ParsePointerCall(currentOperation); break; case OperationCode.Castclass: case OperationCode.Conv_I: case OperationCode.Conv_I1: case OperationCode.Conv_I2: case OperationCode.Conv_I4: case OperationCode.Conv_I8: case OperationCode.Conv_Ovf_I: case OperationCode.Conv_Ovf_I_Un: case OperationCode.Conv_Ovf_I1: case OperationCode.Conv_Ovf_I1_Un: case OperationCode.Conv_Ovf_I2: case OperationCode.Conv_Ovf_I2_Un: case OperationCode.Conv_Ovf_I4: case OperationCode.Conv_Ovf_I4_Un: case OperationCode.Conv_Ovf_I8: case OperationCode.Conv_Ovf_I8_Un: case OperationCode.Conv_Ovf_U: case OperationCode.Conv_Ovf_U_Un: case OperationCode.Conv_Ovf_U1: case OperationCode.Conv_Ovf_U1_Un: case OperationCode.Conv_Ovf_U2: case OperationCode.Conv_Ovf_U2_Un: case OperationCode.Conv_Ovf_U4: case OperationCode.Conv_Ovf_U4_Un: case OperationCode.Conv_Ovf_U8: case OperationCode.Conv_Ovf_U8_Un: case OperationCode.Conv_R_Un: case OperationCode.Conv_R4: case OperationCode.Conv_R8: case OperationCode.Conv_U: case OperationCode.Conv_U1: case OperationCode.Conv_U2: case OperationCode.Conv_U4: case OperationCode.Conv_U8: case OperationCode.Unbox: case OperationCode.Unbox_Any: expression = this.ParseConversion(currentOperation); break; case OperationCode.Ckfinite: this.PopOperandStack(); Debug.Assert(false); //if code out there actually uses this, I need to know sooner rather than later. //TODO: need a code model statement for this instruction. break; case OperationCode.Constrained_: //This prefix is redundant and is not represented in the code model. break; case OperationCode.Cpblk: var copyMemory = new CopyMemoryStatement(); copyMemory.NumberOfBytesToCopy = this.PopOperandStack(); copyMemory.SourceAddress = this.PopOperandStack(); copyMemory.TargetAddress = this.PopOperandStack(); statement = copyMemory; break; case OperationCode.Cpobj: expression = this.ParseCopyObject(); break; case OperationCode.Dup: statement = this.ParseDup(); break; case OperationCode.Endfilter: statement = this.ParseEndfilter(); break; case OperationCode.Endfinally: statement = new EndFinally(); break; case OperationCode.Initblk: var fillMemory = new FillMemoryStatement(); fillMemory.NumberOfBytesToFill = this.PopOperandStack(); fillMemory.FillValue = this.PopOperandStack(); fillMemory.TargetAddress = this.PopOperandStack(); statement = fillMemory; break; case OperationCode.Initobj: statement = this.ParseInitObject(currentOperation); break; case OperationCode.Isinst: expression = this.ParseCastIfPossible(currentOperation); break; case OperationCode.Jmp: Debug.Assert(false); //if code out there actually uses this, I need to know sooner rather than later. //TODO: need a code model statement for this instruction. break; case OperationCode.Ldarg: case OperationCode.Ldarg_0: case OperationCode.Ldarg_1: case OperationCode.Ldarg_2: case OperationCode.Ldarg_3: case OperationCode.Ldarg_S: case OperationCode.Ldloc: case OperationCode.Ldloc_0: case OperationCode.Ldloc_1: case OperationCode.Ldloc_2: case OperationCode.Ldloc_3: case OperationCode.Ldloc_S: case OperationCode.Ldfld: case OperationCode.Ldsfld: expression = this.ParseBoundExpression(currentOperation); break; case OperationCode.Ldarga: case OperationCode.Ldarga_S: case OperationCode.Ldflda: case OperationCode.Ldsflda: case OperationCode.Ldloca: case OperationCode.Ldloca_S: case OperationCode.Ldftn: case OperationCode.Ldvirtftn: expression = this.ParseAddressOf(currentOperation); break; case OperationCode.Ldc_I4: case OperationCode.Ldc_I4_0: case OperationCode.Ldc_I4_1: case OperationCode.Ldc_I4_2: case OperationCode.Ldc_I4_3: case OperationCode.Ldc_I4_4: case OperationCode.Ldc_I4_5: case OperationCode.Ldc_I4_6: case OperationCode.Ldc_I4_7: case OperationCode.Ldc_I4_8: case OperationCode.Ldc_I4_M1: case OperationCode.Ldc_I4_S: case OperationCode.Ldc_I8: case OperationCode.Ldc_R4: case OperationCode.Ldc_R8: case OperationCode.Ldnull: case OperationCode.Ldstr: expression = this.ParseCompileTimeConstant(currentOperation); break; case OperationCode.Ldind_I: case OperationCode.Ldind_I1: case OperationCode.Ldind_I2: case OperationCode.Ldind_I4: case OperationCode.Ldind_I8: case OperationCode.Ldind_R4: case OperationCode.Ldind_R8: case OperationCode.Ldind_Ref: case OperationCode.Ldind_U1: case OperationCode.Ldind_U2: case OperationCode.Ldind_U4: case OperationCode.Ldobj: expression = this.ParseAddressDereference(currentOperation); break; case OperationCode.Ldlen: expression = this.ParseVectorLength(); break; case OperationCode.Ldtoken: expression = ParseToken(currentOperation); break; case OperationCode.Localloc: expression = this.ParseStackArrayCreate(); break; case OperationCode.Mkrefany: expression = this.ParseMakeTypedReference(currentOperation); break; case OperationCode.Neg: expression = this.ParseUnaryOperation(new UnaryNegation()); break; case OperationCode.Not: expression = this.ParseUnaryOperation(new OnesComplement()); break; case OperationCode.Newobj: expression = this.ParseCreateObjectInstance(currentOperation); break; case OperationCode.No_: Debug.Assert(false); //if code out there actually uses this, I need to know sooner rather than later. //TODO: need object model support break; case OperationCode.Nop: statement = new EmptyStatement(); break; case OperationCode.Pop: statement = this.ParsePop(); break; case OperationCode.Readonly_: this.sawReadonly = true; break; case OperationCode.Refanytype: expression = this.ParseGetTypeOfTypedReference(); break; case OperationCode.Refanyval: expression = this.ParseGetValueOfTypedReference(currentOperation); break; case OperationCode.Ret: statement = this.ParseReturn(); break; case OperationCode.Rethrow: statement = new RethrowStatement(); break; case OperationCode.Sizeof: expression = ParseSizeOf(currentOperation); break; case OperationCode.Starg: case OperationCode.Starg_S: case OperationCode.Stelem: case OperationCode.Stelem_I: case OperationCode.Stelem_I1: case OperationCode.Stelem_I2: case OperationCode.Stelem_I4: case OperationCode.Stelem_I8: case OperationCode.Stelem_R4: case OperationCode.Stelem_R8: case OperationCode.Stelem_Ref: case OperationCode.Stfld: case OperationCode.Stind_I: case OperationCode.Stind_I1: case OperationCode.Stind_I2: case OperationCode.Stind_I4: case OperationCode.Stind_I8: case OperationCode.Stind_R4: case OperationCode.Stind_R8: case OperationCode.Stind_Ref: case OperationCode.Stloc: case OperationCode.Stloc_0: case OperationCode.Stloc_1: case OperationCode.Stloc_2: case OperationCode.Stloc_3: case OperationCode.Stloc_S: case OperationCode.Stobj: case OperationCode.Stsfld: statement = this.ParseAssignment(currentOperation); break; case OperationCode.Switch: statement = this.ParseSwitchInstruction(currentOperation); break; case OperationCode.Tail_: this.sawTailCall = true; break; case OperationCode.Throw: statement = this.ParseThrow(); break; case OperationCode.Unaligned_: this.alignment = (byte)currentOperation.Value; break; case OperationCode.Volatile_: this.sawVolatile = true; break; } if (expression != null) { if (this.host.PreserveILLocations) { expression.Locations.Add(currentOperation.Location); } this.operandStack.Push(expression); } else if (statement != null) { this.TurnOperandStackIntoPushStatements(currentBlock); currentBlock.Statements.Add(statement); if (this.host.PreserveILLocations) { if (this.lastLocation != null) { statement.Locations.Add(this.lastLocation); this.lastLocation = null; } } else if (this.lastSourceLocation != null) { statement.Locations.Add(this.lastSourceLocation); this.lastSourceLocation = null; } } }
public override void TraverseChildren(IGotoStatement gotoStatement) { if (gotoStatement == this.backwardsBranch) { if (this.currentIf != null && this.currentIf.TrueBranch == this.currentBlock && this.currentIf.FalseBranch is EmptyStatement) { this.ifContainingBackwardsBranch = this.currentIf; this.blockContainingIfContainingBackwardsBranch = this.blockContainingCurrentIf; } } this.gotosAlreadyTraversed.Add(gotoStatement); base.TraverseChildren(gotoStatement); }
internal static uint GetStartOffset(BasicBlock<Instruction> basicBlock) { Contract.Assume(basicBlock != null); Contract.Assume(basicBlock.Instructions.Count > 0); return basicBlock.Instructions[0].Operation.Offset; }
public override void TraverseChildren(IBlockStatement block) { var savedCurrentBlock = this.currentBlock; var bb = (BasicBlock)block; this.currentBlock = bb; while (true) { var n = bb.Statements.Count; if (n == 0) break; for (int i = 0; i < n-1; i++) this.Traverse(bb.Statements[i]); var bbb = bb.Statements[n-1] as BasicBlock; if (bbb == null || this.loopHeader == null) { this.Traverse(bb.Statements[n-1]); break; } bb = bbb; } this.Traverse(this.currentBlock); this.currentBlock = savedCurrentBlock; }
public override void TraverseChildren(IConditionalStatement conditionalStatement) { this.currentIf = conditionalStatement; this.blockContainingCurrentIf = this.currentBlock; base.TraverseChildren(conditionalStatement); }
private void DecompileTryBody(BasicBlock b, BasicBlock firstHandler, TryCatchFinallyStatement tryStatement) { tryStatement.TryBody = GetBasicBlockUpto(b, firstHandler.StartOffset); BasicBlock tryBody = tryStatement.TryBody as BasicBlock; int startPoint = 0; if (tryBody != null && tryBody.Statements.Count > 0) { ILabeledStatement labeledStatement = tryBody.Statements[0] as ILabeledStatement; if (labeledStatement != null) { tryBody.Statements.RemoveAt(0); b.Statements.Insert(startPoint, labeledStatement); startPoint++; } } b.Statements.Insert(startPoint, tryStatement); }
private static void DecompileHandler(BasicBlock containingBlock, BasicBlock handlerBlock, TryCatchFinallyStatement tryStatement) { if (handlerBlock.ExceptionInformation.HandlerKind == HandlerKind.Finally) { tryStatement.FinallyBody = handlerBlock; } else if (handlerBlock.ExceptionInformation.HandlerKind == HandlerKind.Fault) { tryStatement.FaultBody = handlerBlock; } else { CatchClause catchClause = new CatchClause(); catchClause.Body = handlerBlock; catchClause.ExceptionType = handlerBlock.ExceptionInformation.ExceptionType; if (handlerBlock.ExceptionInformation.HandlerKind == HandlerKind.Catch) { catchClause.ExceptionContainer = ExtractExceptionContainer(handlerBlock); } else if (handlerBlock.ExceptionInformation.HandlerKind == HandlerKind.Filter) { catchClause.FilterCondition = ExtractFilterCondition(handlerBlock); } tryStatement.CatchClauses.Add(catchClause); } //Remove handler from statements in containing block containingBlock.Statements[containingBlock.Statements.Count-1] = GetBasicBlockStartingAt(handlerBlock, handlerBlock.ExceptionInformation.HandlerEndOffset); RemoveEndFinally(handlerBlock); }
private static void RemoveEndFinally(BasicBlock handlerBlock) { while (handlerBlock != null) { int i = handlerBlock.Statements.Count-1; if (i < 0) return; if (handlerBlock.Statements[i] is EndFinally) { handlerBlock.Statements.RemoveAt(i); return; } else { handlerBlock = handlerBlock.Statements[i] as BasicBlock; } } }
protected override void Traverse(BasicBlock b) { for (int i = 0; i < b.Statements.Count; i++) { this.DecompileSwitch(b.Statements, i); } }
public override void TraverseChildren(ILabeledStatement labeledStatement) { if (this.loopHeader == null) { List<IGotoStatement> predecessors; if (this.predecessors.TryGetValue(labeledStatement, out predecessors)) { if (predecessors.Count == 1 && !this.gotosAlreadyTraversed.Contains(predecessors[0])) { this.blockContainingLoopHeader = this.currentBlock; this.loopHeader = labeledStatement; this.backwardsBranch = predecessors[0]; this.ifContainingBackwardsBranch = null; } } } base.TraverseChildren(labeledStatement); }
internal void Traverse(BasicBlock rootBlock) { this.secondPass = false; this.Traverse((IBlockStatement)rootBlock); this.secondPass = true; this.Traverse((IBlockStatement)rootBlock); }
protected override void Traverse(BasicBlock b) { if (b == this.blockContainingLoopHeader && this.ifContainingBackwardsBranch != null && this.blockContainingIfContainingBackwardsBranch == b) { int i = 0; while (b.Statements[i] != this.loopHeader) i++; var loopBody = this.ExtractBasicBlockUpto(b, i+1, this.ifContainingBackwardsBranch); b.Statements[i] = new WhileDoStatement() { Body = loopBody, Condition = this.ifContainingBackwardsBranch.Condition}; RemoveStatement(b, this.ifContainingBackwardsBranch); new WhileLoopDecompiler(this.platformType, this.predecessors).Traverse(loopBody); } }
private void ParseBasicBlock(List<IStatement> list, BasicBlock<Instruction> bb) { Contract.Requires(list != null); Contract.Requires(bb != null); this.FindLastUsesOfLocals(bb); this.operandStack.Clear(); foreach (var stackSetupInstruction in bb.OperandStack) { Contract.Assume(stackSetupInstruction != null); Contract.Assume(!(stackSetupInstruction.Type is Dummy)); this.operandStack.Push(new PopValue() { Type = stackSetupInstruction.Type }); } if (bb.Instructions.Count > 0) { //It might be 0 if there are no il instructions, which happens for some kinds of reference assemblies. var label = this.GetTargetStatement(bb.Instructions[0].Operation.Offset); list.Add(label); foreach (var instruction in bb.Instructions) { Contract.Assume(instruction != null); this.ParseInstruction(instruction, list); } } if (list.Count > 0 && !(list[list.Count-1] is GotoStatement)) this.TurnOperandStackIntoPushStatements(list); }
protected override void Traverse(BasicBlock b) { if (b.NumberOfTryBlocksStartingHere > 0) { BasicBlock firstHandler = null; TryCatchFinallyStatement/*?*/ tryStatement = new TryCatchFinallyStatement(); BasicBlock bb = b; while (b.NumberOfTryBlocksStartingHere-- > 0) { if (bb.Statements.Count > 0) { BasicBlock bbb = bb.Statements[bb.Statements.Count-1] as BasicBlock; while (bbb != null) { if (bbb.ExceptionInformation != null) { if (firstHandler == null) firstHandler = bbb; if (firstHandler.ExceptionInformation.TryEndOffset < bbb.ExceptionInformation.TryEndOffset) { DecompileTryBody(b, firstHandler, tryStatement); tryStatement = new TryCatchFinallyStatement(); firstHandler = bbb; } DecompileHandler(bb, bbb, tryStatement); break; } if (bbb.Statements.Count == 0) break; bb = bbb; bbb = bbb.Statements[bbb.Statements.Count-1] as BasicBlock; } } } DecompileTryBody(b, firstHandler, tryStatement); } }
private bool NextReferenceIsAssignment(ILocalDefinition local, BasicBlock<Instruction> bb, int offset, SetOfObjects blocksAlreadyVisited) { Contract.Requires(bb != null); Contract.Requires(offset >= 0); Contract.Requires(blocksAlreadyVisited != null); blocksAlreadyVisited.Add(bb); for (int i = offset, n = bb.Instructions.Count; i < n; i++) { var instruction = bb.Instructions[i]; switch (instruction.Operation.OperationCode) { case OperationCode.Ldloc: case OperationCode.Ldloc_0: case OperationCode.Ldloc_1: case OperationCode.Ldloc_2: case OperationCode.Ldloc_3: case OperationCode.Ldloc_S: case OperationCode.Ldloca: case OperationCode.Ldloca_S: if (instruction.Operation.Value == local) return false; break; case OperationCode.Stloc: case OperationCode.Stloc_0: case OperationCode.Stloc_1: case OperationCode.Stloc_2: case OperationCode.Stloc_3: case OperationCode.Stloc_S: if (instruction.Operation.Value == local) return true; break; } } var result = true; foreach (var successor in this.cdfg.SuccessorsFor(bb)) { Contract.Assume(successor != null); if (blocksAlreadyVisited.Contains(successor)) continue; result &= this.NextReferenceIsAssignment(local, successor, 0, blocksAlreadyVisited); if (!result) break; } return result; }
private void DecompileIfThenElseStatement(BasicBlock b, int i) { List<IStatement> statements = b.Statements; ConditionalStatement/*?*/ conditionalStatement = statements[i++] as ConditionalStatement; if (conditionalStatement == null) return; IExpression condition; var trueBranch = UnwrapSingletonBlock(conditionalStatement.TrueBranch); GotoStatement/*?*/ gotoAfterThen = trueBranch as GotoStatement; if (gotoAfterThen == null) { gotoAfterThen = UnwrapSingletonBlock(conditionalStatement.FalseBranch) as GotoStatement; if (gotoAfterThen == null || !(trueBranch is EmptyStatement)) return; condition = conditionalStatement.Condition; } else { if (!(conditionalStatement.FalseBranch is EmptyStatement)) return; LogicalNot not = new LogicalNot(); not.Operand = conditionalStatement.Condition; condition = not; } //At this point we have: //if (!condition) goto afterThen; var afterThen = this.FindLabeledStatement(statements, i, gotoAfterThen.TargetStatement.Label); if (afterThen == null) return; List<IGotoStatement> branchesToThisLabel; if (this.predecessors.TryGetValue(afterThen, out branchesToThisLabel)) branchesToThisLabel.Remove(gotoAfterThen); BasicBlock ifBlock = this.ExtractBasicBlockUpto(b, i, afterThen); GotoStatement/*?*/ gotoEndif = this.RemoveAndReturnLastGotoStatement(ifBlock); this.Traverse(ifBlock); BasicBlock elseBlock = null; if (gotoEndif != null) { var endif = this.FindLabeledStatement(statements, i, gotoEndif.TargetStatement.Label); if (endif != null) { if (this.predecessors.TryGetValue(gotoEndif.TargetStatement, out branchesToThisLabel)) branchesToThisLabel.Remove(gotoEndif); elseBlock = this.ExtractBasicBlockUpto(b, i, gotoEndif.TargetStatement); elseBlock.Statements.Add(gotoEndif.TargetStatement); this.Traverse(elseBlock); elseBlock.Statements.Remove(gotoEndif.TargetStatement); } else { ifBlock.Statements.Add(gotoEndif); } } conditionalStatement.Condition = condition; conditionalStatement.TrueBranch = ifBlock; if (elseBlock != null) conditionalStatement.FalseBranch = elseBlock; else conditionalStatement.FalseBranch = new EmptyStatement(); return; }
/// <summary> /// /// </summary> /// <param name="offset"></param> /// <param name="addLabel"></param> /// <returns></returns> protected BasicBlock GetOrCreateBlock(uint offset, bool addLabel) { BasicBlock result; if (!this.blockFor.TryGetValue(offset, out result)) { result = new BasicBlock(offset); this.blockFor.Add(offset, result); } if (addLabel && result.Statements.Count == 0) { LabeledStatement label = new LabeledStatement(); label.Label = this.nameTable.GetNameFor("IL_" + offset.ToString("x4")); label.Statement = new EmptyStatement(); result.Statements.Add(label); this.targetStatementFor.Add(offset, label); } return result; }
internal static uint GetStartOffset(BasicBlock <Instruction> basicBlock) { Contract.Assume(basicBlock != null); Contract.Assume(basicBlock.Instructions.Count > 0); return(basicBlock.Instructions[0].Operation.Offset); }
/// <summary> /// Perform different phases approppriate for normal, MoveNext, or iterator source method bodies. /// </summary> /// <param name="rootBlock"></param> /// <returns></returns> protected IBlockStatement Transform(BasicBlock rootBlock) { new TypeInferencer((INamedTypeDefinition)this.ilMethodBody.MethodDefinition.ContainingType, this.host).Traverse(rootBlock); new PatternDecompiler(this, this.predecessors).Traverse(rootBlock); new RemoveBranchConditionLocals(this).Traverse(rootBlock); new Unstacker(this).Visit(rootBlock); new TypeInferencer((INamedTypeDefinition)this.ilMethodBody.MethodDefinition.ContainingType, this.host).Traverse(rootBlock); new TryCatchDecompiler(this.host.PlatformType, this.predecessors).Traverse(rootBlock); new IfThenElseDecompiler(this.host.PlatformType, this.predecessors).Traverse(rootBlock); new SwitchDecompiler(this.host.PlatformType, this.predecessors).Traverse(rootBlock); if ((this.options & DecompilerOptions.Loops) != 0) { new WhileLoopDecompiler(this.host.PlatformType, this.predecessors).Traverse(rootBlock); new ForLoopDecompiler(this.host.PlatformType, this.predecessors).Traverse(rootBlock); } new BlockRemover().Traverse(rootBlock); new DeclarationAdder().Traverse(this, rootBlock); new EmptyStatementRemover().Traverse(rootBlock); IBlockStatement result = rootBlock; if ((this.options & DecompilerOptions.Iterators) != 0) { IMethodBody moveNextILBody = this.FindClosureMoveNext(rootBlock); if (moveNextILBody != Dummy.MethodBody) { if (this.privateHelperTypesToRemove == null) this.privateHelperTypesToRemove = new List<ITypeDefinition>(1); this.privateHelperTypesToRemove.Add(moveNextILBody.MethodDefinition.ContainingTypeDefinition); var moveNextBody = new MoveNextSourceMethodBody(this.ilMethodBody, moveNextILBody, this.host, this.sourceLocationProvider, this.localScopeProvider, this.options); result = moveNextBody.TransformedBlock; } } result = new CompilationArtifactRemover(this, (this.options & DecompilerOptions.AnonymousDelegates) != 0).RemoveCompilationArtifacts((BlockStatement)result); var bb = result as BasicBlock; if (bb != null) { new UnreferencedLabelRemover(this).Traverse(bb); new TypeInferencer((INamedTypeDefinition)this.ilMethodBody.MethodDefinition.ContainingType, this.host).Traverse(bb); } return result; }
private static ILocalDefinition ExtractExceptionContainer(BasicBlock bb) { ILocalDefinition result = Dummy.LocalVariable; if (bb.Statements.Count < 1) return result; ExpressionStatement es = bb.Statements[0] as ExpressionStatement; if (es == null) return result; if (es.Expression is Pop) { bb.Statements.RemoveAt(0); return result; } Assignment assign = es.Expression as Assignment; if (assign == null) return result; if (!(assign.Source is Pop)) return result; if (!(assign.Target.Definition is ILocalDefinition)) return result; result = (ILocalDefinition)assign.Target.Definition; bb.Statements.RemoveAt(0); if (bb.LocalVariables != null && bb.LocalVariables.Remove(result)) return result; if (bb.Statements.Count > 0) { BasicBlock nbb = bb.Statements[0] as BasicBlock; if (nbb != null && nbb.LocalVariables != null) nbb.LocalVariables.Remove(result); } return result; }
// For the first assignment to a local variable in a block before a control statement is hit, // if the local variable is not mentioned previously, we turn this assignment into a local declaration. private void AddDeclarationsWithInitialValues(IEnumerable<ILocalDefinition> localVariables, BasicBlock block) { List<ILocalDefinition> topLevelLocals = new List<ILocalDefinition>(localVariables); List<ILocalDefinition> localsMet = new List<ILocalDefinition>(); for (int i = 0; i < block.Statements.Count; i++) { if (topLevelLocals.Count == 0) break; IExpressionStatement expressionStatement = block.Statements[i] as IExpressionStatement; if (expressionStatement != null) { IAssignment assignment = expressionStatement.Expression as IAssignment; if (assignment != null) { ILocalDefinition localDef = assignment.Target.Definition as ILocalDefinition; if (localDef != null && topLevelLocals.Contains(localDef) && !localsMet.Contains(localDef) && !this.declaredLocals.ContainsKey(localDef)) { LocalDeclarationStatement localDecl = new LocalDeclarationStatement() { LocalVariable = localDef, InitialValue = assignment.Source, Locations = new List<ILocation>(expressionStatement.Locations), }; this.declaredLocals.Add(localDef, true); block.Statements[i] = localDecl; topLevelLocals.Remove(localDef); localsMet.Add(localDef); } } } LocalFinder finder = new LocalFinder(); finder.Traverse(block.Statements[i]); foreach (ILocalDefinition local in finder.FoundLocals) { if (!localsMet.Contains(local)) localsMet.Add(local); } //Once we see a statement that can transfer control somewhere else, we //no longer know that any subsequent assignment dominates all references //and hence cannot postpone adding the declaration until we can unify it with the assignment. IGotoStatement gotoStatement = block.Statements[i] as IGotoStatement; if (gotoStatement != null) break; IConditionalStatement conditionalStatement = block.Statements[i] as IConditionalStatement; if (conditionalStatement != null) break; ISwitchStatement switchStatement = block.Statements[i] as ISwitchStatement; if (switchStatement != null) break; IForEachStatement foreachStatement = block.Statements[i] as IForEachStatement; if (foreachStatement != null) break; IForStatement forStatement = block.Statements[i] as IForStatement; if (forStatement != null) break; ITryCatchFinallyStatement tryStatement = block.Statements[i] as ITryCatchFinallyStatement; if (tryStatement != null) break; } }
protected override void Traverse(BasicBlock b) { for (int i = 0; i < b.Statements.Count; i++) { this.DecompileIfThenElseStatement(b, i); } }