public static void Run(DecompilerContext context, ILBlock method) { if (!context.Settings.YieldReturn) return; // abort if enumerator decompilation is disabled var yrd = new YieldReturnDecompiler(); yrd.context = context; if (!yrd.MatchEnumeratorCreationPattern(method)) return; yrd.enumeratorType = yrd.enumeratorCtor.DeclaringType; #if DEBUG if (Debugger.IsAttached) { yrd.Run(); } else { #endif try { yrd.Run(); } catch (SymbolicAnalysisFailedException) { return; } #if DEBUG } #endif method.Body.Clear(); method.EntryGoto = null; method.Body.AddRange(yrd.newBody); // Repeat the inlining/copy propagation optimization because the conversion of field access // to local variables can open up additional inlining possibilities. ILInlining inlining = new ILInlining(method); inlining.InlineAllVariables(); inlining.CopyPropagation(); }
public static void Run(DecompilerContext context, ILBlock method) { if (!context.Settings.YieldReturn) return; // abort if enumerator decompilation is disabled var yrd = new YieldReturnDecompiler(); yrd.context = context; if (!yrd.MatchEnumeratorCreationPattern(method)) return; yrd.enumeratorType = yrd.enumeratorCtor.DeclaringType; #if DEBUG if (Debugger.IsAttached) { yrd.Run(); } else { #endif try { yrd.Run(); } catch (YieldAnalysisFailedException) { return; } #if DEBUG } #endif method.Body.Clear(); method.EntryGoto = null; method.Body.AddRange(yrd.newBody); }
public void RemoveGotos(ILBlock method) { // Build the navigation data parent[method] = null; foreach (ILNode node in method.GetSelfAndChildrenRecursive<ILNode>()) { ILNode previousChild = null; foreach (ILNode child in node.GetChildren()) { if (parent.ContainsKey(child)) throw new Exception("The following expression is linked from several locations: " + child.ToString()); parent[child] = node; if (previousChild != null) nextSibling[previousChild] = child; previousChild = child; } if (previousChild != null) nextSibling[previousChild] = null; } // Simplify gotos bool modified; do { modified = false; foreach (ILExpression gotoExpr in method.GetSelfAndChildrenRecursive<ILExpression>(e => e.Code == ILCode.Br || e.Code == ILCode.Leave)) { modified |= TrySimplifyGoto(gotoExpr); } } while(modified); RemoveRedundantCode(method); }
public static void RunStep1(DecompilerContext context, ILBlock method) { if (!context.Settings.AsyncAwait) return; // abort if async decompilation is disabled var yrd = new AsyncDecompiler(); yrd.context = context; if (!yrd.MatchTaskCreationPattern(method)) return; #if DEBUG if (Debugger.IsAttached) { yrd.Run(); } else { #endif try { yrd.Run(); } catch (SymbolicAnalysisFailedException) { return; } #if DEBUG } #endif context.CurrentMethodIsAsync = true; method.Body.Clear(); method.EntryGoto = null; method.Body.AddRange(yrd.newTopLevelBody); ILAstOptimizer.RemoveRedundantCode(method); }
public ILBlockTranslator(AssemblyTranslator translator, DecompilerContext context, MethodReference methodReference, MethodDefinition methodDefinition, ILBlock ilb, IEnumerable<ILVariable> parameters, IEnumerable<ILVariable> allVariables) { Translator = translator; Context = context; ThisMethodReference = methodReference; ThisMethod = methodDefinition; Block = ilb; SpecialIdentifiers = new JSIL.SpecialIdentifiers(TypeSystem); if (methodReference.HasThis) Variables.Add("this", JSThisParameter.New(methodReference.DeclaringType, methodReference)); foreach (var parameter in parameters) { if ((parameter.Name == "this") && (parameter.OriginalParameter.Index == -1)) continue; ParameterNames.Add(parameter.Name); Variables.Add(parameter.Name, new JSParameter(parameter.Name, parameter.Type, methodReference)); } foreach (var variable in allVariables) { var v = JSVariable.New(variable, methodReference); if (Variables.ContainsKey(v.Identifier)) { v = new JSVariable(variable.OriginalVariable.Name, variable.Type, methodReference); RenamedVariables[variable] = v; Variables.Add(v.Identifier, v); } else { Variables.Add(v.Identifier, v); } } }
public BlockStatement CreateMethodBody() { if (methodDef.Body == null) return null; context.CancellationToken.ThrowIfCancellationRequested(); ILBlock ilMethod = new ILBlock(); ILAstBuilder astBuilder = new ILAstBuilder(); ilMethod.Body = astBuilder.Build(methodDef, true); context.CancellationToken.ThrowIfCancellationRequested(); ILAstOptimizer bodyGraph = new ILAstOptimizer(); bodyGraph.Optimize(context, ilMethod); context.CancellationToken.ThrowIfCancellationRequested(); var allVariables = ilMethod.GetSelfAndChildrenRecursive<ILExpression>().Select(e => e.Operand as ILVariable).Where(v => v != null && !v.IsGenerated).Distinct(); NameVariables.AssignNamesToVariables(methodDef.Parameters.Select(p => p.Name), allVariables, ilMethod); context.CancellationToken.ThrowIfCancellationRequested(); Ast.BlockStatement astBlock = TransformBlock(ilMethod); CommentStatement.ReplaceAll(astBlock); // convert CommentStatements to Comments foreach (ILVariable v in localVariablesToDefine) { DeclareVariableInSmallestScope.DeclareVariable(astBlock, AstBuilder.ConvertType(v.Type), v.Name); } return astBlock; }
public static void Run(DecompilerContext context, ILBlock method, List<ILNode> list_ILNode, Func<ILBlock, ILInlining> getILInlining) { if (!context.Settings.YieldReturn) return; // abort if enumerator decompilation is disabled var yrd = new YieldReturnDecompiler(); yrd.context = context; if (!yrd.MatchEnumeratorCreationPattern(method)) return; yrd.enumeratorType = yrd.enumeratorCtor.DeclaringType; #if DEBUG && CRASH_IN_DEBUG_MODE if (Debugger.IsAttached) { yrd.Run(); } else { #endif try { yrd.Run(); } catch (SymbolicAnalysisFailedException) { return; } #if DEBUG && CRASH_IN_DEBUG_MODE } #endif method.Body.Clear(); method.EntryGoto = null; method.Body.AddRange(yrd.newBody);//TODO: Make sure that the removed ILRanges from Clear() above is saved in the new body // Repeat the inlining/copy propagation optimization because the conversion of field access // to local variables can open up additional inlining possibilities. var inlining = getILInlining(method); inlining.InlineAllVariables(); inlining.CopyPropagation(list_ILNode); }
public void Optimize(ILBlock method) { foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) { SplitToMovableBlocks(block); } foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().Where(b => !(b is ILMoveableBlock)).ToList()) { ControlFlowGraph graph; graph = BuildGraph(block.Body, block.EntryPoint); graph.ComputeDominance(); graph.ComputeDominanceFrontier(); block.Body = FindLoops(new HashSet<ControlFlowNode>(graph.Nodes.Skip(3)), graph.EntryPoint, true); } foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().Where(b => !(b is ILMoveableBlock)).ToList()) { ControlFlowGraph graph; graph = BuildGraph(block.Body, block.EntryPoint); graph.ComputeDominance(); graph.ComputeDominanceFrontier(); block.Body = FindConditions(new HashSet<ControlFlowNode>(graph.Nodes.Skip(3)), graph.EntryPoint); } // OrderNodes(method); FlattenNestedMovableBlocks(method); SimpleGotoRemoval(method); RemoveDeadLabels(method); }
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) { if (!method.HasBody) { return; } ILAstBuilder astBuilder = new ILAstBuilder(); ILBlock ilMethod = new ILBlock(); ilMethod.Body = astBuilder.Build(method, inlineVariables); if (abortBeforeStep != null) { DecompilerContext context = new DecompilerContext(method.Module) { CurrentType = method.DeclaringType, CurrentMethod = method }; new ILAstOptimizer().Optimize(context, ilMethod, abortBeforeStep.Value); } var allVariables = ilMethod.GetSelfAndChildrenRecursive<ILExpression>().Select(e => e.Operand as ILVariable) .Where(v => v != null && !v.IsParameter).Distinct(); foreach (ILVariable v in allVariables) { output.WriteDefinition(v.Name, v); if (v.Type != null) { output.Write(" : "); if (v.IsPinned) output.Write("pinned "); v.Type.WriteTo(output, ILNameSyntax.ShortTypeName); } output.WriteLine(); } output.WriteLine(); foreach (ILNode node in ilMethod.Body) { node.WriteTo(output); output.WriteLine(); } }
protected override ILBlock VisitBlock(ILBlock block) { currentScope++; var result = base.VisitBlock(block); currentScope--; if (block.Body.Count == 0) return result; var toOffset = block.LastILOffset(); if (toOffset < 0) return result; foreach (var start in starts.Where(kvp => kvp.Key.Item2 == currentScope + 1).ToList()) { starts.Remove(start.Key); List<ILExpression> args; if (block.Body.Last().Match(ILCode.Ret, out args) && args.Count == 1 && args[0].MatchLdloc(start.Key.Item1)) continue; // Returning the variable UsingRanges.Add(new ILRange { From = start.Value, To = toOffset }); } return result; }
public BlockStatement CreateMethodBody() { if (methodDef.Body == null) return null; context.CancellationToken.ThrowIfCancellationRequested(); ILBlock ilMethod = new ILBlock(); ILAstBuilder astBuilder = new ILAstBuilder(); ilMethod.Body = astBuilder.Build(methodDef, true); context.CancellationToken.ThrowIfCancellationRequested(); ILAstOptimizer bodyGraph = new ILAstOptimizer(); bodyGraph.Optimize(context, ilMethod); context.CancellationToken.ThrowIfCancellationRequested(); NameVariables.AssignNamesToVariables(methodDef.Parameters.Select(p => p.Name), astBuilder.Variables, ilMethod); context.CancellationToken.ThrowIfCancellationRequested(); Ast.BlockStatement astBlock = TransformBlock(ilMethod); CommentStatement.ReplaceAll(astBlock); // convert CommentStatements to Comments foreach (ILVariable v in localVariablesToDefine) { DeclareVariableInSmallestScope.DeclareVariable(astBlock, AstBuilder.ConvertType(v.Type), v.Name); } return astBlock; }
public override void DecompileMethod(MethodDef method, ITextOutput output, DecompilationOptions options) { WriteComment(output, "Method: "); output.WriteDefinition(IdentifierEscaper.Escape(method.FullName), method, TextTokenType.Comment, false); output.WriteLine(); if (!method.HasBody) { return; } StartKeywordBlock(output, ".body", method); ILAstBuilder astBuilder = new ILAstBuilder(); ILBlock ilMethod = new ILBlock(); DecompilerContext context = new DecompilerContext(method.Module) { CurrentType = method.DeclaringType, CurrentMethod = method }; ilMethod.Body = astBuilder.Build(method, inlineVariables, context); if (abortBeforeStep != null) { new ILAstOptimizer().Optimize(context, ilMethod, abortBeforeStep.Value); } if (context.CurrentMethodIsAsync) { output.Write("async", TextTokenType.Keyword); output.Write('/', TextTokenType.Operator); output.WriteLine("await", TextTokenType.Keyword); } var allVariables = ilMethod.GetSelfAndChildrenRecursive<ILExpression>().Select(e => e.Operand as ILVariable) .Where(v => v != null && !v.IsParameter).Distinct(); foreach (ILVariable v in allVariables) { output.WriteDefinition(IdentifierEscaper.Escape(v.Name), v, v.IsParameter ? TextTokenType.Parameter : TextTokenType.Local); if (v.Type != null) { output.WriteSpace(); output.Write(':', TextTokenType.Operator); output.WriteSpace(); if (v.IsPinned) { output.Write("pinned", TextTokenType.Keyword); output.WriteSpace(); } v.Type.WriteTo(output, ILNameSyntax.ShortTypeName); } if (v.IsGenerated) { output.WriteSpace(); output.Write('[', TextTokenType.Operator); output.Write("generated", TextTokenType.Keyword); output.Write(']', TextTokenType.Operator); } output.WriteLine(); } var memberMapping = new MemberMapping(method); foreach (ILNode node in ilMethod.Body) { node.WriteTo(output, memberMapping); if (!node.WritesNewLine) output.WriteLine(); } output.AddDebugSymbols(memberMapping); EndKeywordBlock(output); }
/// <summary> /// Inlines the stloc instruction at block.Body[pos] into the next instruction, if possible. /// </summary> public static bool InlineIfPossible(ILBlock block, int pos, ILBlock method) { if (InlineIfPossible((ILExpression)block.Body[pos], block.Body.ElementAtOrDefault(pos+1), method)) { block.Body.RemoveAt(pos); return true; } return false; }
public static void AssignNamesToVariables(IEnumerable<string> existingNames, IEnumerable<ILVariable> variables, ILBlock methodBody) { NameVariables nv = new NameVariables(); nv.AddExistingNames(existingNames); foreach (ILVariable varDef in variables) { nv.AssignNameToVariable(varDef, methodBody.GetSelfAndChildrenRecursive<ILExpression>()); } }
public void FindConditions(ILBlock block) { if (block.Body.Count > 0) { ControlFlowGraph graph; graph = BuildGraph(block.Body, (ILLabel)block.EntryGoto.Operand); graph.ComputeDominance(context.CancellationToken); graph.ComputeDominanceFrontier(); block.Body = FindConditions(new HashSet<ControlFlowNode>(graph.Nodes.Skip(3)), graph.EntryPoint); } }
public static void Run(DecompilerContext context, ILBlock method) { TypeAnalysis ta = new TypeAnalysis(); ta.context = context; ta.module = context.CurrentMethod.Module; ta.typeSystem = ta.module.TypeSystem; ta.method = method; ta.InferTypes(method); ta.InferRemainingStores(); }
Ast.BlockStatement TransformBlock(ILBlock block) { Ast.BlockStatement astBlock = new BlockStatement(); if (block != null) { foreach(ILNode node in block.GetChildren()) { astBlock.AddRange(TransformNode(node)); } } return astBlock; }
public void FindLoops(ILBlock block) { if (block.Body.Count > 0) { ControlFlowGraph graph; graph = BuildGraph(block.Body, (ILLabel)block.EntryGoto.Operand); graph.ComputeDominance(context.VerifyProgress); graph.ComputeDominanceFrontier(); block.Body = FindLoops(new HashSet<ControlFlowNode>(graph.Nodes.Skip(3)), graph.EntryPoint, false); } }
public BlockStatement CreateMethodBody() { if (methodDef.Body == null) return null; ILBlock ilMethod = new ILBlock(); ILAstBuilder astBuilder = new ILAstBuilder(); ilMethod.Body = astBuilder.Build(methodDef, true); ILAstOptimizer bodyGraph = new ILAstOptimizer(); bodyGraph.Optimize(ilMethod); List<string> intNames = new List<string>(new string[] {"i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t"}); Dictionary<string, int> typeNames = new Dictionary<string, int>(); foreach(ILVariable varDef in astBuilder.Variables) { if (varDef.Type.FullName == Constants.Int32 && intNames.Count > 0) { varDef.Name = intNames[0]; intNames.RemoveAt(0); } else { string name; if (varDef.Type.IsArray) { name = "array"; } else if (!typeNameToVariableNameDict.TryGetValue(varDef.Type.FullName, out name)) { name = varDef.Type.Name; // remove the 'I' for interfaces if (name.Length >= 3 && name[0] == 'I' && char.IsUpper(name[1]) && char.IsLower(name[2])) name = name.Substring(1); // remove the backtick (generics) int pos = name.IndexOf('`'); if (pos >= 0) name = name.Substring(0, pos); if (name.Length == 0) name = "obj"; else name = char.ToLower(name[0]) + name.Substring(1); } if (!typeNames.ContainsKey(name)) { typeNames.Add(name, 0); } int count = ++(typeNames[name]); if (count > 1) { name += count.ToString(); } varDef.Name = name; } // Ast.VariableDeclaration astVar = new Ast.VariableDeclaration(varDef.Name); // Ast.LocalVariableDeclaration astLocalVar = new Ast.LocalVariableDeclaration(astVar); // astLocalVar.TypeReference = new Ast.TypeReference(varDef.VariableType.FullName); // astBlock.Children.Add(astLocalVar); } Ast.BlockStatement astBlock = TransformBlock(ilMethod); CommentStatement.ReplaceAll(astBlock); // convert CommentStatements to Comments return astBlock; }
public static void Transform(ILBlock method) { // TODO: move this somewhere else // Eliminate 'dups': foreach (ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) { for (int i = 0; i < expr.Arguments.Count; i++) { if (expr.Arguments[i].Code == ILCode.Dup) expr.Arguments[i] = expr.Arguments[i].Arguments[0]; } } var newArrPattern = new StoreToVariable(new ILExpression(ILCode.Newarr, ILExpression.AnyOperand, new ILExpression(ILCode.Ldc_I4, ILExpression.AnyOperand))); var arg1 = new StoreToVariable(new LoadFromVariable(newArrPattern)) { MustBeGenerated = true }; var arg2 = new StoreToVariable(new LoadFromVariable(newArrPattern)) { MustBeGenerated = true }; var initializeArrayPattern = new ILCall( "System.Runtime.CompilerServices.RuntimeHelpers", "InitializeArray", new LoadFromVariable(arg1), new ILExpression(ILCode.Ldtoken, ILExpression.AnyOperand)); foreach (ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) { for (int i = block.Body.Count - 1; i >= 0; i--) { if (!newArrPattern.Match(block.Body[i])) continue; ILExpression newArrInst = ((ILExpression)block.Body[i]).Arguments[0]; int arrayLength = (int)newArrInst.Arguments[0].Operand; if (arrayLength == 0) continue; if (arg1.Match(block.Body.ElementAtOrDefault(i + 1)) && arg2.Match(block.Body.ElementAtOrDefault(i + 2))) { if (initializeArrayPattern.Match(block.Body.ElementAtOrDefault(i + 3))) { if (HandleStaticallyInitializedArray(arg2, block, i, newArrInst, arrayLength)) { i -= ILInlining.InlineInto(block, i + 1, method) - 1; } continue; } } if (i + 1 + arrayLength > block.Body.Count) continue; List<ILExpression> operands = new List<ILExpression>(); for (int j = 0; j < arrayLength; j++) { ILExpression expr = block.Body[i + 1 + j] as ILExpression; if (expr == null || !IsStoreToArray(expr.Code)) break; if (!(expr.Arguments[0].Code == ILCode.Ldloc && expr.Arguments[0].Operand == newArrPattern.LastVariable)) break; if (!(expr.Arguments[1].Code == ILCode.Ldc_I4 && (int)expr.Arguments[1].Operand == j)) break; operands.Add(expr.Arguments[2]); } if (operands.Count == arrayLength) { ((ILExpression)block.Body[i]).Arguments[0] = new ILExpression( ILCode.InitArray, newArrInst.Operand, operands.ToArray()); block.Body.RemoveRange(i + 1, arrayLength); i -= ILInlining.InlineInto(block, i + 1, method) - 1; } } } }
bool MatchEnumeratorCreationPattern(ILBlock method) { if (method.Body.Count == 0) return false; ILExpression newObj; if (method.Body.Count == 1) { // ret(newobj(...)) if (method.Body[0].Match(ILCode.Ret, out newObj)) return MatchEnumeratorCreationNewObj(newObj, out enumeratorCtor); else return false; } // stloc(var_1, newobj(..) ILVariable var1; if (!method.Body[0].Match(ILCode.Stloc, out var1, out newObj)) return false; if (!MatchEnumeratorCreationNewObj(newObj, out enumeratorCtor)) return false; int i; for (i = 1; i < method.Body.Count; i++) { // stfld(..., ldloc(var_1), ldloc(parameter)) FieldReference storedField; ILExpression ldloc, loadParameter; if (!method.Body[i].Match(ILCode.Stfld, out storedField, out ldloc, out loadParameter)) break; ILVariable loadedVar, loadedArg; if (!ldloc.Match(ILCode.Ldloc, out loadedVar) || !loadParameter.Match(ILCode.Ldloc, out loadedArg)) return false; storedField = GetFieldDefinition(storedField); if (loadedVar != var1 || storedField == null || !loadedArg.IsParameter) return false; fieldToParameterMap[(FieldDefinition)storedField] = loadedArg; } ILVariable var2; ILExpression ldlocForStloc2; if (i < method.Body.Count && method.Body[i].Match(ILCode.Stloc, out var2, out ldlocForStloc2)) { // stloc(var_2, ldloc(var_1)) if (ldlocForStloc2.Code != ILCode.Ldloc || ldlocForStloc2.Operand != var1) return false; i++; } else { // the compiler might skip the above instruction in release builds; in that case, it directly returns stloc.Operand var2 = var1; } ILExpression retArg; if (i < method.Body.Count && method.Body[i].Match(ILCode.Ret, out retArg)) { // ret(ldloc(var_2)) if (retArg.Code == ILCode.Ldloc && retArg.Operand == var2) { return true; } } return false; }
public static void Run(DecompilerContext context, ILBlock method) { TypeAnalysis ta = new TypeAnalysis(); ta.context = context; ta.module = context.CurrentMethod.Module; ta.typeSystem = ta.module.TypeSystem; ta.method = method; ta.CreateDependencyGraph(method); ta.IdentifySingleLoadVariables(); ta.RunInference(); }
public void FindLoops(ILBlock block) { if (block.Body.Count > 0) { ControlFlowGraph graph; graph = BuildGraph(block.Body, (ILLabel)block.EntryGoto.Operand); graph.ComputeDominance(context.CancellationToken); graph.ComputeDominanceFrontier(); //TODO: Keep ILRanges when writing to Body block.Body = FindLoops(new HashSet<ControlFlowNode>(graph.Nodes.Skip(3)), graph.EntryPoint, false); } }
private static ILBlock Decompile(MethodDefinition method) { bool inlineVariables = false; ILAstBuilder astBuilder = new ILAstBuilder(); ILBlock ilMethod = new ILBlock(); DecompilerContext context = new DecompilerContext(method.Module) { CurrentType = method.DeclaringType, CurrentMethod = method }; ilMethod.Body = astBuilder.Build(method, inlineVariables, context); new ILAstOptimizer().Optimize(context, ilMethod, ILAstOptimizationStep.None); return ilMethod; }
public BlockStatement CreateMethodBody(IEnumerable<ParameterDeclaration> parameters, ConcurrentDictionary<int, IEnumerable<ILVariable>> localVariables) { if (methodDef.Body == null) return null; if (localVariables == null) throw new ArgumentException("localVariables must be instantiated"); context.CancellationToken.ThrowIfCancellationRequested(); ILBlock ilMethod = new ILBlock(); ILAstBuilder astBuilder = new ILAstBuilder(); ilMethod.Body = astBuilder.Build(methodDef, true); context.CancellationToken.ThrowIfCancellationRequested(); ILAstOptimizer bodyGraph = new ILAstOptimizer(); bodyGraph.Optimize(context, ilMethod); context.CancellationToken.ThrowIfCancellationRequested(); var allVariables = ilMethod.GetSelfAndChildrenRecursive<ILExpression>().Select(e => e.Operand as ILVariable) .Where(v => v != null && !v.IsParameter).Distinct(); Debug.Assert(context.CurrentMethod == methodDef); NameVariables.AssignNamesToVariables(context, astBuilder.Parameters, allVariables, ilMethod); if (parameters != null) { foreach (var pair in (from p in parameters join v in astBuilder.Parameters on p.Annotation<ParameterDefinition>() equals v.OriginalParameter select new { p, v.Name })) { pair.p.Name = pair.Name; } } context.CancellationToken.ThrowIfCancellationRequested(); Ast.BlockStatement astBlock = TransformBlock(ilMethod); CommentStatement.ReplaceAll(astBlock); // convert CommentStatements to Comments Statement insertionPoint = astBlock.Statements.FirstOrDefault(); foreach (ILVariable v in localVariablesToDefine) { AstType type; if (v.Type.ContainsAnonymousType()) type = new SimpleType("var"); else type = AstBuilder.ConvertType(v.Type); var newVarDecl = new VariableDeclarationStatement(type, v.Name); astBlock.Statements.InsertBefore(insertionPoint, newVarDecl); } // store the variables - used for debugger int token = methodDef.MetadataToken.ToInt32(); localVariables.AddOrUpdate(token, allVariables, (key, oldValue) => allVariables); return astBlock; }
Ast.BlockStatement TransformBlock(ILBlock block) { Ast.BlockStatement astBlock = new BlockStatement(); if (block != null) { if (block.EntryGoto != null) astBlock.Add((Statement)TransformExpression(block.EntryGoto)); foreach(ILNode node in block.Body) { astBlock.AddRange(TransformNode(node)); } } return astBlock; }
public static void Run(DecompilerContext context, ILBlock method) { PeepholeTransforms transforms = new PeepholeTransforms(); transforms.context = context; transforms.method = method; PeepholeTransform[] blockTransforms = { ArrayInitializers.Transform(method), transforms.CachedDelegateInitialization }; Func<ILExpression, ILExpression>[] exprTransforms = { EliminateDups, HandleDecimalConstants }; // Traverse in post order so that nested blocks are transformed first. This is required so that // patterns on the parent block can assume that all nested blocks are already transformed. foreach (var node in TreeTraversal.PostOrder<ILNode>(method, c => c != null ? c.GetChildren() : null)) { ILBlock block = node as ILBlock; ILExpression expr; if (block != null) { // go through the instructions in reverse so that transforms can build up nested structures inside-out for (int i = block.Body.Count - 1; i >= 0; i--) { context.CancellationToken.ThrowIfCancellationRequested(); expr = block.Body[i] as ILExpression; if (expr != null) { // apply expr transforms to top-level expr in block foreach (var t in exprTransforms) expr = t(expr); block.Body[i] = expr; } // apply block transforms foreach (var t in blockTransforms) { t(block, ref i); Debug.Assert(i <= block.Body.Count && i >= 0); if (i == block.Body.Count) // special case: retry all transforms break; } } } expr = node as ILExpression; if (expr != null) { // apply expr transforms to all arguments for (int i = 0; i < expr.Arguments.Count; i++) { ILExpression arg = expr.Arguments[i]; foreach (var t in exprTransforms) arg = t(arg); expr.Arguments[i] = arg; } } } }
/// <summary> /// Inlines instructions before pos into block.Body[pos]. /// </summary> /// <returns>The number of instructions that were inlined.</returns> public static int InlineInto(ILBlock block, int pos, ILBlock method) { int count = 0; while (--pos >= 0) { ILExpression expr = block.Body[pos] as ILExpression; if (expr == null || expr.Code != ILCode.Stloc) break; if (InlineIfPossible(block, pos, method)) count++; else break; } return count; }
public SimpleControlFlow(DecompilerContext context, ILBlock method) { this.context = context; this.typeSystem = context.CurrentMethod.Module.TypeSystem; foreach(ILLabel target in method.GetSelfAndChildrenRecursive<ILExpression>(e => e.IsBranch()).SelectMany(e => e.GetBranchTargets())) { labelGlobalRefCount[target] = labelGlobalRefCount.GetOrDefault(target) + 1; } foreach(ILBasicBlock bb in method.GetSelfAndChildrenRecursive<ILBasicBlock>()) { foreach(ILLabel label in bb.GetChildren().OfType<ILLabel>()) { labelToBasicBlock[label] = bb; } } }
/// <summary> /// Inlines 'expr' into 'next', if possible. /// </summary> public static bool InlineIfPossible(ILExpression expr, ILNode next, ILBlock method) { if (expr.Code != ILCode.Stloc) throw new ArgumentException("expr must be stloc"); // ensure the variable is accessed only a single time if (method.GetSelfAndChildrenRecursive<ILExpression>().Count(e => e != expr && e.Operand == expr.Operand) != 1) return false; ILExpression parent; int pos; if (FindLoadInNext(next as ILExpression, (ILVariable)expr.Operand, out parent, out pos) == true) { parent.Arguments[pos] = expr.Arguments[0]; return true; } return false; }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Get the ID (i.e. ASM label) of the method to load a pointer to Types.MethodInfo methodInfo = conversionState.TheILLibrary.GetMethodInfo(theOp.MethodToCall); string methodID = methodInfo.ID; bool addExternalLabel = methodID != conversionState.Input.TheMethodInfo.ID; //If we want to load the pointer at a specified IL op number: if (theOp.LoadAtILOpAfterOp != null) { ILBlock anILBlock = conversionState.TheILLibrary.GetILBlock(methodInfo); int index = anILBlock.ILOps.IndexOf(theOp.LoadAtILOpAfterOp); index++; methodID = ASM.ASMBlock.GenerateLabel(methodID, anILBlock.PositionOf(anILBlock.ILOps[index])); } else if (theOp.LoadAtILOffset != int.MaxValue) { //Append the IL sub-label to the ID ILBlock anILBlock = conversionState.TheILLibrary.GetILBlock(methodInfo); methodID = ASM.ASMBlock.GenerateLabel(methodID, anILBlock.PositionOf(anILBlock.At(theOp.LoadAtILOffset))); //Note: This is used by try/catch/finally blocks for pushing pointers // to catch/finally handlers and filters } if (addExternalLabel) { conversionState.AddExternalLabel(methodID); } //Push the pointer to the function conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = methodID }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); }
internal void Build(ILBlock block) { var node = block.FirstChild; while (node != null) { switch (node.NodeType) { case ILNodeType.Block: Build((ILBlock)node); break; case ILNodeType.Instruction: Build((ILInstruction)node); break; } node = node.NextSibling; } }
public void Transform() { if (this.pipeline == null) { throw new InvalidOperationException("Transformer already used."); } foreach (IPostTransform handler in this.pipeline) { handler.Initialize(this); this.RootScope.ProcessBasicBlocks <ILInstrList>(block => { this.Block = (ILBlock)block; handler.Transform(this); }); } this.pipeline = null; }
IEnumerable <ILVariable> GetVariables(ILBlock ilMethod) { foreach (var n in ilMethod.GetSelfAndChildrenRecursive(new List <ILNode>())) { var expr = n as ILExpression; if (expr != null) { var v = expr.Operand as ILVariable; if (v != null && !v.IsParameter) { yield return(v); } continue; } var cb = n as ILTryCatchBlock.CatchBlockBase; if (cb != null && cb.ExceptionVariable != null) { yield return(cb.ExceptionVariable); } } }
public bool WriteWithLiaison(object target, Interval field_update_interval, object liaison, Buffer buffer) { if (object_liaison_writer == null) { object_liaison_writer = GetTargetType().CreateDynamicMethodDelegateWithForcedParameterTypes <ObjectLiaisonWriter>(delegate(ILValue il_target, ILValue il_field_update_interval, ILValue il_liaison, ILValue il_buffer) { ILBlock block = new ILBlock(); ILLocal il_to_return = block.CreateNamedLocal(typeof(bool), "to_return"); block.AddStatements( target_serializer_prop_groups .Convert(g => g.GenerateWrite(il_target, il_field_update_interval, type_update_interval, il_liaison, il_to_return, il_buffer)) ); block.AddStatement(new ILReturn(il_to_return)); return(block); }, GetTargetType(), typeof(Interval), GetLiaisonType(), typeof(Buffer)); } return(object_liaison_writer(target, field_update_interval, liaison, buffer)); }
public static bool RunOptimization(this ILBlock block, Func <IList <ILNode>, ILExpression, int, bool> optimization) { bool modified = false; foreach (ILBasicBlock bb in block.Body) { for (int i = bb.Body.Count - 1; i >= 0; i--) { ILExpression expr = bb.Body.ElementAtOrDefault(i) as ILExpression; if (expr != null && optimization(bb.Body, expr, i)) { modified = true; } } } if (Context.Debug) { block.FixParents(); } return(modified); }
public uint ComputeOffset(ILBlock block, uint offset) { foreach (var instr in block.Content) { instr.Offset = offset; offset += 2; if (instr.Operand != null) { if (instr.Operand is ILRegister) { offset++; } else if (instr.Operand is ILImmediate) { var value = ((ILImmediate)instr.Operand).Value; if (value is uint || value is int || value is float) { offset += 4; } else if (value is ulong || value is long || value is double) { offset += 8; } else { throw new NotSupportedException(); } } else if (instr.Operand is ILRelReference) { offset += 4; } else { throw new NotSupportedException(); } } } return(offset); }
protected override ILBlock CreateNewBlock() { if (Context.Version != UndertaleVersion.V10001) { throw new Exception("Cannot compile new code using old"); } Locals = new Dictionary <string, ILVariable>(); // Don't need any of that above since we don't do asms anymore var error = new ErrorContext(name); ILBlock dblock = new ILBlock(); dblock.Body = new Dissasembler.NewByteCodeToAst().Build(this, error); ILBlock block = new ILAstBuilder().Build(dblock, Locals, error); Debug.Assert(block != null); block.FixParents(); return(block); }
public void Initialize(ILTransformer tr) { this.trampoline = null; tr.RootScope.ProcessBasicBlocks <ILInstrList>(b => { if (b.Content.Any(instr => instr.IR != null && instr.IR.Annotation == SMCBlock.AddressPart2)) { this.trampoline = (ILBlock)b; } }); if (this.trampoline == null) { return; } CFG.ScopeBlock scope = tr.RootScope.SearchBlock(this.trampoline).Last(); this.newTrampoline = new SMCBlock(this.trampoline.Id, this.trampoline.Content); scope.Content[scope.Content.IndexOf(this.trampoline)] = this.newTrampoline; this.adrKey = tr.VM.Random.Next(); this.newTrampoline.Key = (byte)tr.VM.Random.Next(); }
public override void Preprocess(ILPreprocessState preprocessState, ILOp theOp) { Types.MethodInfo methodInfo = preprocessState.TheILLibrary.GetMethodInfo(theOp.MethodToCall); if (theOp.LoadAtILOpAfterOp != null) { ILBlock anILBlock = preprocessState.TheILLibrary.GetILBlock(methodInfo); int index = anILBlock.ILOps.IndexOf(theOp.LoadAtILOpAfterOp); if (index == -1) { throw new NullReferenceException("LoadAtILOpAfterOp not found in IL block!"); } index++; anILBlock.ILOps[index].LabelRequired = true; } else if (theOp.LoadAtILOffset != int.MaxValue) { int offset = theOp.LoadAtILOffset; ILOp theLoadedOp = preprocessState.TheILLibrary.GetILBlock(methodInfo).At(offset); theLoadedOp.LabelRequired = true; } }
void FixIfStatements(ILBlock method) { bool modified; do { // We have to do this here as we want clean if statments // ILSpy does this later when it converts the ILAst to normal Ast, but since were skipping that // step, this "should" make if statements a bit cleaner modified = false; foreach (ILCondition ilCond in method.GetSelfAndChildrenRecursive <ILCondition>()) { if (ilCond.TrueBlock.Body.Count == 0 && (ilCond.FalseBlock != null && ilCond.FalseBlock.Body.Count != 0)) { // If we have an empty true block but stuff in the falls block, negate the condition and swap blocks var swap = ilCond.TrueBlock; ilCond.TrueBlock = ilCond.FalseBlock; ilCond.FalseBlock = swap; ilCond.Condition = ilCond.Condition.NegateCondition(); modified |= true; } } } while (modified); }
protected void WriteSingleLineOrBlock(ILBlock block) { ILExpression e = null; if (SingleExpressionInBlock(block, out e)) { if (e.ToString().Length + this.Column > 80) { WriteLine(); } this.Indent++; Write(' '); Write(e); Write(';'); this.Indent--; } else { WriteLine(" {"); Write(block, true); Write("}"); } }
static public FingerPrintOperation CreateFingerPrintOperation(this Type item) { MethodInfoEX get_hash_code_ex_method = typeof(TypeExtensions_Finger_Create).GetStaticMethod <object>("GetHashCodeEX"); return(item.CreateDynamicMethodDelegate <FingerPrintOperation>("FingerPrint_" + item.Name, delegate(MethodBase method){ ILBlock body = new ILBlock(); ILLocal obj = body.CreateNamedLocal(item, "this", method.GetTechnicalILParameter(0)); ILLocal hash = body.CreateNamedLocal(typeof(int), "hash", 17); foreach (FieldInfo field in item.GetAllInstanceFields()) { body.AddStatement( new ILAssign( hash, hash * 23 + get_hash_code_ex_method.GetStaticILMethodInvokation(obj.GetILField(field)) ) ); } body.AddStatement(new ILReturn(hash)); return body; })); }
private void Obfuscate(ILBlock block) { var node = block.FirstChild; while (node != null) { switch (node.NodeType) { case ILNodeType.Block: { Obfuscate((ILBlock)node); } break; case ILNodeType.Instruction: { Obfuscate((ILInstruction)node); } break; } node = node.NextSibling; } }
private bool Map(ILBlock block) { bool changed = false; var node = block.FirstChild; while (node != null) { switch (node.NodeType) { case ILNodeType.Block: changed |= Map((ILBlock)node); break; case ILNodeType.Instruction: changed |= Map((ILInstruction)node); break; } node = node.NextSibling; } return(changed); }
protected override ILBlock VisitBlock(ILBlock block) { currentScope++; var result = base.VisitBlock(block); currentScope--; if (block.Body.Count == 0) { return(result); } var toOffset = block.LastILOffset(); if (toOffset < 0) { return(result); } foreach (var start in starts.Where(kvp => kvp.Key.Item2 == currentScope + 1).ToList()) { starts.Remove(start.Key); List <ILExpression> args; if (block.Body.Last().Match(ILCode.Ret, out args) && args.Count == 1 && args[0].MatchLdloc(start.Key.Item1)) { continue; // Returning the variable } UsingRanges.Add(new ILRange { From = start.Value, To = toOffset }); } return(result); }
public ILBlock Build(ILBlock method, Dictionary <string, ILVariable> locals, ErrorContext error) { if (method == null) { throw new ArgumentNullException("method"); } if (error == null) { throw new ArgumentNullException("error"); } if (locals == null) { throw new ArgumentNullException("locals"); } this.error = error; this.locals = locals; error.CheckDebugThenSave(method, "raw.txt", true); // Not sure I need this pass now // WE doo now, This converts popenv to either breaks or branchs. This is needed // as if you return from a pushenv, a popenv break is called FixAllPushesAndPopenv(method.Body); // makes sure all pushes have no operands and are all expressions for latter matches Optimize.RemoveRedundantCode(method); foreach (var block in method.GetSelfAndChildrenRecursive <ILBlock>()) { Optimize.SplitToBasicBlocks(block, true); } error.CheckDebugThenSave(method, "basic_blocks.txt"); bool modified = false; bool debug_once = true; foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>()) { do { modified = false; do // Does all the internal things to a blocks for other passes to be easyer { modified = false; modified |= block.RunOptimization(MatchVariablePush); // checks pushes for instance or indexs for vars modified |= block.RunOptimization(SimpleAssignments); modified |= block.RunOptimization(AssignValueTo); modified |= block.RunOptimization(ComplexAssignments); // basicly self increment, this SHOULDN'T cross block boundrys modified |= block.RunOptimization(SimplifyBranches); // Any resolved pushes are put into a branch argument modified |= block.RunOptimization(CombineCall); // Any resolved pushes are put into a branch argument modified |= block.RunOptimization(CombineExpressions); modified |= block.RunOptimization(FixTempReturnValues); } while (modified); if (Context.Debug) { if (debug_once) { error.CheckDebugThenSave(method, "basic_blocks_resolved.txt"); debug_once = false; } } // modified |= block.RunOptimization(new SimpleControlFlow(method,error).DetectSwitch); // modified |= block.RunOptimization(new SimpleControlFlow(method, error).DetectSwitchAndConvertToBranches); modified |= block.RunOptimization(new SimpleControlFlow(method, error).DetectSwitch_GenerateSwitch); modified |= block.RunOptimization(MultiDimenionArray); modified |= block.RunOptimization(Optimize.SimplifyBoolTypes); modified |= block.RunOptimization(Optimize.SimplifyLogicNot); modified |= block.RunOptimization(PushEnviromentFix); // match all with's with expressions modified |= block.RunOptimization(new SimpleControlFlow(method, error).SimplifyShortCircuit); modified |= block.RunOptimization(new SimpleControlFlow(method, error).SimplifyTernaryOperator); modified |= block.RunOptimization(new SimpleControlFlow(method, error).MatchRepeatStructure); modified |= block.RunOptimization(new SimpleControlFlow(method, error).JoinBasicBlocks); // somewhere, so bug, is leaving an empty block, I think because of switches // It screws up the flatten block check for some reason modified |= block.RunOptimization(new SimpleControlFlow(method, error).RemoveRedundentBlocks); // want to run this at the end to fix return stuff } while (modified); } error.CheckDebugThenSave(method, "before_loops.txt"); if (BeforeConditionsDebugSainityCheck(method)) { return(null); // sainity check, evething must be ready for this } foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>()) { new LoopsAndConditions(error).FindLoops(block); } error.CheckDebugThenSave(method, "before_conditions.txt"); foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>()) { new LoopsAndConditions(error).FindConditions(block); } error.CheckDebugThenSave(method, "before_flatten.txt"); FlattenBasicBlocks(method); error.CheckDebugThenSave(method, "before_gotos.txt"); Optimize.RemoveRedundantCode(method); new GotoRemoval().RemoveGotos(method); error.CheckDebugThenSave(method, "before_if.txt"); // This is cleaned up in ILSpy latter when its converted to another ast structure, but I clean it up here // cause I don't convert it and mabye not converting all bt's to bf's dosn't // FixIfStatements(method); Optimize.RemoveRedundantCode(method); new GotoRemoval().RemoveGotos(method); error.CheckDebugThenSave(method, "final.txt"); if (AfterLoopsAndConditions(method)) { return(null); // another sanity check } return(method); }
public override void Decompile(MethodDef method, IDecompilerOutput output, DecompilationContext ctx) { WriteCommentBegin(output, true); output.Write("Method: ", BoxedTextColor.Comment); output.Write(IdentifierEscaper.Escape(method.FullName), method, DecompilerReferenceFlags.Definition, BoxedTextColor.Comment); WriteCommentEnd(output, true); output.WriteLine(); if (!method.HasBody) { return; } var bodyInfo = StartKeywordBlock(output, ".body", method); ILAstBuilder astBuilder = new ILAstBuilder(); ILBlock ilMethod = new ILBlock(CodeBracesRangeFlags.MethodBraces); DecompilerContext context = new DecompilerContext(method.Module, MetadataTextColorProvider) { CurrentType = method.DeclaringType, CurrentMethod = method, CalculateBinSpans = ctx.CalculateBinSpans, }; ilMethod.Body = astBuilder.Build(method, inlineVariables, context); if (abortBeforeStep != null) { new ILAstOptimizer().Optimize(context, ilMethod, abortBeforeStep.Value); } if (context.CurrentMethodIsYieldReturn) { output.Write("yield", BoxedTextColor.Keyword); output.Write(" ", BoxedTextColor.Text); output.WriteLine("return", BoxedTextColor.Keyword); } if (context.CurrentMethodIsAsync) { output.Write("async", BoxedTextColor.Keyword); output.Write("/", BoxedTextColor.Punctuation); output.WriteLine("await", BoxedTextColor.Keyword); } var allVariables = ilMethod.GetSelfAndChildrenRecursive <ILExpression>().Select(e => e.Operand as ILVariable) .Where(v => v != null && !v.IsParameter).Distinct(); foreach (ILVariable v in allVariables) { output.Write(IdentifierEscaper.Escape(v.Name), (object)v.OriginalVariable ?? (object)v.OriginalParameter ?? v.Id, DecompilerReferenceFlags.Local | DecompilerReferenceFlags.Definition, v.IsParameter ? BoxedTextColor.Parameter : BoxedTextColor.Local); if (v.Type != null) { output.Write(" ", BoxedTextColor.Text); output.Write(":", BoxedTextColor.Punctuation); output.Write(" ", BoxedTextColor.Text); if (v.IsPinned) { output.Write("pinned", BoxedTextColor.Keyword); output.Write(" ", BoxedTextColor.Text); } v.Type.WriteTo(output, ILNameSyntax.ShortTypeName); } if (v.GeneratedByDecompiler) { output.Write(" ", BoxedTextColor.Text); var start = output.NextPosition; output.Write("[", BoxedTextColor.Punctuation); output.Write("generated", BoxedTextColor.Keyword); var end = output.NextPosition; output.Write("]", BoxedTextColor.Punctuation); output.AddBracePair(new TextSpan(start, 1), new TextSpan(end, 1), CodeBracesRangeFlags.SquareBrackets); } output.WriteLine(); } var builder = new MethodDebugInfoBuilder(method); foreach (ILNode node in ilMethod.Body) { node.WriteTo(output, builder); if (!node.WritesNewLine) { output.WriteLine(); } } output.AddDebugInfo(builder.Create()); EndKeywordBlock(output, bodyInfo, CodeBracesRangeFlags.MethodBraces, addLineSeparator: true); }
private List <ILVariable> PreprocessorCheckUninitializedLocalVarsBranch(ILBlock branch, List <ILVariable> initializedVars) { List <ILVariable> result = new List <ILVariable>(initializedVars); foreach (ILNode node in branch.Body) { if (node is ILExpression) { PreprocessorCheckUninitializedLocalVarsExpression((ILExpression)node, result); } else if (node is ILBlock) { result = PreprocessorCheckUninitializedLocalVarsBranch((ILBlock)node, result); } else if (node is ILTryCatchBlock) { ILTryCatchBlock block = (ILTryCatchBlock)node; List <ILVariable> newResult = new List <ILVariable>(result); if (block.TryBlock != null) { newResult = newResult.Union(PreprocessorCheckUninitializedLocalVarsBranch(block.TryBlock, result)).ToList(); } if (block.FaultBlock != null) { newResult = newResult.Union(PreprocessorCheckUninitializedLocalVarsBranch(block.FaultBlock, result)).ToList(); } if (block.FinallyBlock != null) { newResult = newResult.Union(PreprocessorCheckUninitializedLocalVarsBranch(block.FinallyBlock, result)).ToList(); } if (block.CatchBlocks != null) { foreach (ILTryCatchBlock.CatchBlock c in block.CatchBlocks) { newResult = newResult.Union(PreprocessorCheckUninitializedLocalVarsBranch(c, result)).ToList(); } } result = newResult; } else if (node is ILWhileLoop) { PreprocessorCheckUninitializedLocalVarsExpression(((ILWhileLoop)node).Condition, result); result = PreprocessorCheckUninitializedLocalVarsBranch(((ILWhileLoop)node).BodyBlock, result); } else if (node is ILCondition) { ILCondition cond = (ILCondition)node; PreprocessorCheckUninitializedLocalVarsExpression(cond.Condition, result); List <ILVariable> fromTrue = PreprocessorCheckUninitializedLocalVarsBranch(cond.TrueBlock, result); List <ILVariable> fromFalse = PreprocessorCheckUninitializedLocalVarsBranch(cond.FalseBlock, result); result = fromTrue.Union(fromFalse).ToList(); } else if (node is ILSwitch) { ILSwitch sw = (ILSwitch)node; PreprocessorCheckUninitializedLocalVarsExpression(sw.Condition, result); List <ILVariable> newResult = new List <ILVariable>(result); foreach (var cas in sw.CaseBlocks) { newResult = newResult.Union(PreprocessorCheckUninitializedLocalVarsBranch(cas, result)).ToList(); } result = newResult; } } return(result); }
public void AddBlock(MethodDef method, ILBlock block) { basicBlocks.Add(Tuple.Create(method, block)); }
Dictionary <int, Action <XamlContext, XElement> > ExtractConnectionId(XamlContext ctx, MethodDef method) { var context = new DecompilerContext(method.Module) { CurrentType = method.DeclaringType, CurrentMethod = method, CancellationToken = ctx.CancellationToken }; var body = new ILBlock(new ILAstBuilder().Build(method, true, context)); new ILAstOptimizer().Optimize(context, body); var sw = body.GetSelfAndChildrenRecursive <ILSwitch>().FirstOrDefault(); if (sw == null) { return(null); } var connIds = new Dictionary <int, Action <XamlContext, XElement> >(); foreach (var cas in sw.CaseBlocks) { if (cas.Values == null) { continue; } Action <XamlContext, XElement> cb = null; foreach (var node in cas.Body) { var expr = node as ILExpression; if (expr == null) { continue; } switch (expr.Code) { case ILCode.Stfld: cb += new FieldAssignment { FieldName = ((IField)expr.Operand).Name }.Callback; break; case ILCode.Call: case ILCode.Callvirt: var operand = (IMethod)expr.Operand; if (operand.Name == "AddHandler" && operand.DeclaringType.FullName == "System.Windows.UIElement") { // Attached event var re = expr.Arguments[1]; var ctor = expr.Arguments[2]; var reField = re.Operand as IField; if (re.Code != ILCode.Ldsfld || ctor.Code != ILCode.Newobj || ctor.Arguments.Count != 2 || ctor.Arguments[1].Code != ILCode.Ldftn) { cb += new Error { Msg = string.Format(dnSpy_BamlDecompiler_Resources.Error_AttachedEvent, reField.Name) }.Callback; break; } var handler = (IMethod)ctor.Arguments[1].Operand; string evName = reField.Name; if (evName.EndsWith("Event")) { evName = evName.Substring(0, evName.Length - 5); } cb += new EventAttachment { AttachedType = reField.DeclaringType.ResolveTypeDefThrow(), EventName = evName, MethodName = handler.Name }.Callback; } else { // CLR event var add = operand.ResolveMethodDefThrow(); var ev = add.DeclaringType.Events.FirstOrDefault(e => e.AddMethod == add); var ctor = expr.Arguments[1]; if (ev == null || ctor.Code != ILCode.Newobj || ctor.Arguments.Count != 2 || ctor.Arguments[1].Code != ILCode.Ldftn) { cb += new Error { Msg = string.Format(dnSpy_BamlDecompiler_Resources.Error_AttachedEvent, add.Name) }.Callback; break; } var handler = (IMethod)ctor.Arguments[1].Operand; cb += new EventAttachment { EventName = ev.Name, MethodName = handler.Name }.Callback; } break; } } if (cb != null) { foreach (var id in cas.Values) { connIds[id] = cb; } } } return(connIds.Count == 0 ? null : connIds); }
public void WriteData(ILBlock block, BinaryWriter writer) { uint offset = 0; SequencePoint prevSeq = null; uint prevOffset = 0; foreach (var instr in block.Content) { if (rt.dbgWriter != null && instr.IR.ILAST is ILASTExpression) { var expr = (ILASTExpression)instr.IR.ILAST; var seq = expr.CILInstr == null ? null : expr.CILInstr.SequencePoint; if (seq != null && seq.StartLine != 0xfeefee && (prevSeq == null || !Equals(seq, prevSeq))) { if (prevSeq != null) { uint len = offset - prevOffset, line = (uint)prevSeq.StartLine; var doc = prevSeq.Document.Url; rt.dbgWriter.AddSequencePoint(block, prevOffset, len, doc, line); } prevSeq = seq; prevOffset = offset; } } writer.Write(rt.Descriptor.Architecture.OpCodes[instr.OpCode]); // Leave a padding to let BasicBlockChunk fixup block exit key writer.Write((byte)rt.Descriptor.Random.Next()); offset += 2; if (instr.Operand != null) { if (instr.Operand is ILRegister) { writer.Write(rt.Descriptor.Architecture.Registers[((ILRegister)instr.Operand).Register]); offset++; } else if (instr.Operand is ILImmediate) { var value = ((ILImmediate)instr.Operand).Value; if (value is int) { writer.Write((int)value); offset += 4; } else if (value is uint) { writer.Write((uint)value); offset += 4; } else if (value is long) { writer.Write((long)value); offset += 8; } else if (value is ulong) { writer.Write((ulong)value); offset += 8; } else if (value is float) { writer.Write((float)value); offset += 4; } else if (value is double) { writer.Write((double)value); offset += 8; } } else { throw new NotSupportedException(); } } } if (prevSeq != null) { uint len = offset - prevOffset, line = (uint)prevSeq.StartLine; var doc = prevSeq.Document.Url; rt.dbgWriter.AddSequencePoint(block, prevOffset, len, doc, line); } }
public override void Decompile(MethodDef method, IDecompilerOutput output, DecompilationContext ctx) { WriteCommentBegin(output, true); output.Write("Method: ", BoxedTextColor.Comment); output.Write(IdentifierEscaper.Escape(method.FullName), method, DecompilerReferenceFlags.Definition, BoxedTextColor.Comment); WriteCommentEnd(output, true); output.WriteLine(); if (!method.HasBody) { return; } var bodyInfo = StartKeywordBlock(output, ".body", method); ILAstBuilder astBuilder = new ILAstBuilder(); ILBlock ilMethod = new ILBlock(CodeBracesRangeFlags.MethodBraces); DecompilerContext context = new DecompilerContext(settingsVersion, method.Module, MetadataTextColorProvider) { CurrentType = method.DeclaringType, CurrentMethod = method, CalculateILSpans = ctx.CalculateILSpans, }; ilMethod.Body = astBuilder.Build(method, inlineVariables, context); var stateMachineKind = StateMachineKind.None; MethodDef? inlinedMethod = null; AsyncMethodDebugInfo?asyncInfo = null; string? compilerName = null; if (!(abortBeforeStep is null)) { var optimizer = new ILAstOptimizer(); optimizer.Optimize(context, ilMethod, out stateMachineKind, out inlinedMethod, out asyncInfo, abortBeforeStep.Value); compilerName = optimizer.CompilerName; } if (context.CurrentMethodIsYieldReturn) { output.Write("yield", BoxedTextColor.Keyword); output.Write(" ", BoxedTextColor.Text); output.WriteLine("return", BoxedTextColor.Keyword); } if (context.CurrentMethodIsAsync) { output.Write("async", BoxedTextColor.Keyword); output.Write("/", BoxedTextColor.Punctuation); output.WriteLine("await", BoxedTextColor.Keyword); } var allVariables = ilMethod.GetSelfAndChildrenRecursive <ILExpression>().Select(e => e.Operand as ILVariable) .Where(v => !(v is null) && !v.IsParameter).Distinct(); foreach (ILVariable v in allVariables) { output.Write(IdentifierEscaper.Escape(v.Name), v.GetTextReferenceObject(), DecompilerReferenceFlags.Local | DecompilerReferenceFlags.Definition, v.IsParameter ? BoxedTextColor.Parameter : BoxedTextColor.Local); if (!(v.Type is null)) { output.Write(" ", BoxedTextColor.Text); output.Write(":", BoxedTextColor.Punctuation); output.Write(" ", BoxedTextColor.Text); if (v.IsPinned) { output.Write("pinned", BoxedTextColor.Keyword); output.Write(" ", BoxedTextColor.Text); } v.Type.WriteTo(output, ILNameSyntax.ShortTypeName); } if (v.GeneratedByDecompiler) { output.Write(" ", BoxedTextColor.Text); var start = output.NextPosition; output.Write("[", BoxedTextColor.Punctuation); output.Write("generated", BoxedTextColor.Keyword); var end = output.NextPosition; output.Write("]", BoxedTextColor.Punctuation); output.AddBracePair(new TextSpan(start, 1), new TextSpan(end, 1), CodeBracesRangeFlags.SquareBrackets); } output.WriteLine(); } var localVariables = new HashSet <ILVariable>(GetVariables(ilMethod)); var builder = new MethodDebugInfoBuilder(settingsVersion, stateMachineKind, inlinedMethod ?? method, !(inlinedMethod is null) ? method : null, CreateSourceLocals(localVariables), CreateSourceParameters(localVariables), asyncInfo); builder.CompilerName = compilerName; foreach (ILNode node in ilMethod.Body) { node.WriteTo(output, builder); if (!node.WritesNewLine) { output.WriteLine(); } } output.AddDebugInfo(builder.Create()); EndKeywordBlock(output, bodyInfo, CodeBracesRangeFlags.MethodBraces, addLineSeparator: true); }
internal void AddHelper(MethodDef method, ScopeBlock rootScope, ILBlock entry) { methodMap[method] = Tuple.Create(rootScope, entry); }
string GenerateNameForVariable(ILVariable variable, ILBlock methodBody) { string proposedName = null; if (variable.Type == context.CurrentType.Module.TypeSystem.Int32) { // test whether the variable might be a loop counter bool isLoopCounter = false; foreach (ILWhileLoop loop in methodBody.GetSelfAndChildrenRecursive <ILWhileLoop>()) { ILExpression expr = loop.Condition; while (expr != null && expr.Code == ILCode.LogicNot) { expr = expr.Arguments[0]; } if (expr != null) { switch (expr.Code) { case ILCode.Clt: case ILCode.Clt_Un: case ILCode.Cgt: case ILCode.Cgt_Un: case ILCode.Cle: case ILCode.Cle_Un: case ILCode.Cge: case ILCode.Cge_Un: ILVariable loadVar; if (expr.Arguments[0].Match(ILCode.Ldloc, out loadVar) && loadVar == variable) { isLoopCounter = true; } break; } } } if (isLoopCounter) { // For loop variables, use i,j,k,l,m,n for (char c = 'i'; c <= maxLoopVariableName; c++) { if (!typeNames.ContainsKey(c.ToString())) { proposedName = c.ToString(); break; } } } } if (string.IsNullOrEmpty(proposedName)) { var proposedNameForStores = (from expr in methodBody.GetSelfAndChildrenRecursive <ILExpression>() where expr.Code == ILCode.Stloc && expr.Operand == variable select GetNameFromExpression(expr.Arguments.Single()) ).Except(fieldNamesInCurrentType).ToList(); if (proposedNameForStores.Count == 1) { proposedName = proposedNameForStores[0]; } } if (string.IsNullOrEmpty(proposedName)) { var proposedNameForLoads = (from expr in methodBody.GetSelfAndChildrenRecursive <ILExpression>() from i in Enumerable.Range(0, expr.Arguments.Count) let arg = expr.Arguments[i] where arg.Code == ILCode.Ldloc && arg.Operand == variable select GetNameForArgument(expr, i) ).Except(fieldNamesInCurrentType).ToList(); if (proposedNameForLoads.Count == 1) { proposedName = proposedNameForLoads[0]; } } if (string.IsNullOrEmpty(proposedName)) { proposedName = GetNameByType(variable.Type); } // remove any numbers from the proposed name int number; proposedName = SplitName(proposedName, out number); if (!typeNames.ContainsKey(proposedName)) { typeNames.Add(proposedName, 0); } int count = ++typeNames[proposedName]; if (count > 1) { return(proposedName + count.ToString()); } else { return(proposedName); } }
public Dictionary <int, EventRegistration[]> DecompileEventMappings(string fullTypeName) { var result = new Dictionary <int, EventRegistration[]>(); TypeDefinition type = this.assembly.MainModule.GetType(fullTypeName); if (type == null) { return(result); } MethodDefinition def = null; foreach (var method in type.Methods) { if (method.Name == "System.Windows.Markup.IComponentConnector.Connect") { def = method; break; } } if (def == null) { return(result); } // decompile method and optimize the switch ILBlock ilMethod = new ILBlock(); ILAstBuilder astBuilder = new ILAstBuilder(); ilMethod.Body = astBuilder.Build(def, true); ILAstOptimizer optimizer = new ILAstOptimizer(); var context = new DecompilerContext(type.Module) { CurrentMethod = def, CurrentType = type }; optimizer.Optimize(context, ilMethod, ILAstOptimizationStep.RemoveRedundantCode3); ILSwitch ilSwitch = ilMethod.Body.OfType <ILSwitch>().FirstOrDefault(); ILCondition condition = ilMethod.Body.OfType <ILCondition>().FirstOrDefault(); if (ilSwitch != null) { foreach (var caseBlock in ilSwitch.CaseBlocks) { if (caseBlock.Values == null) { continue; } var events = FindEvents(caseBlock); foreach (int id in caseBlock.Values) { result.Add(id, events); } } } else if (condition != null) { result.Add(1, FindEvents(condition.FalseBlock)); } return(result); }
public static void AssignNamesToVariables(DecompilerContext context, IEnumerable <ILVariable> parameters, IEnumerable <ILVariable> variables, ILBlock methodBody) { NameVariables nv = new NameVariables(); nv.context = context; nv.fieldNamesInCurrentType = context.CurrentType.Fields.Select(f => f.Name).ToList(); // First mark existing variable names as reserved. foreach (string name in context.ReservedVariableNames) { nv.AddExistingName(name); } foreach (var p in parameters) { nv.AddExistingName(p.Name); } foreach (var v in variables) { if (v.IsGenerated) { // don't introduce names for variables generated by ILSpy - keep "expr"/"arg" nv.AddExistingName(v.Name); } else if (v.OriginalVariable != null && context.Settings.UseDebugSymbols) { string varName = v.OriginalVariable.Name; if (string.IsNullOrEmpty(varName) || varName.StartsWith("V_", StringComparison.Ordinal) || !IsValidName(varName)) { // don't use the name from the debug symbols if it looks like a generated name v.Name = null; } else { // use the name from the debug symbols // (but ensure we don't use the same name for two variables) v.Name = nv.GetAlternativeName(varName); } } else { v.Name = null; } } // Now generate names: foreach (ILVariable p in parameters) { if (string.IsNullOrEmpty(p.Name)) { p.Name = nv.GenerateNameForVariable(p, methodBody); } } foreach (ILVariable varDef in variables) { if (string.IsNullOrEmpty(varDef.Name)) { varDef.Name = nv.GenerateNameForVariable(varDef, methodBody); } } }
private void Load(LoadState state, ILBlock block) { var zeroStackSizeNodes = new List <ILNode>(); int instructionCount = 0; bool hasChildren = false; var node = block.FirstChild; while (node != null) { switch (node.NodeType) { case ILNodeType.Instruction: { var instruction = (ILInstruction)node; int stackSize; if (state.StackSizeByInstruction.TryGetValue(instruction, out stackSize) && stackSize == 0) { if (CanBranchAtInstruction(instruction)) { zeroStackSizeNodes.Add(instruction); } } instructionCount++; } break; case ILNodeType.Block: { var tryBlock = node as ILTryBlock; if (tryBlock != null) { if (node.PreviousSibling != null) { zeroStackSizeNodes.Add(tryBlock); } hasChildren = true; instructionCount++; } } break; } node = node.NextSibling; } state.TotalInstructionCount += instructionCount; if (zeroStackSizeNodes.Count > 0) { var blockState = new BlockLoadState(); blockState.Index = state.Blocks.Count; blockState.InstructionCount = instructionCount; blockState.Node = block; blockState.ZeroStackSizeNodes = zeroStackSizeNodes; state.Blocks.Add(blockState); } // Load child blocks if (hasChildren) { node = block.FirstChild; while (node != null) { var tryBlock = node as ILTryBlock; if (tryBlock != null) { Load(state, tryBlock); } node = node.NextSibling; } } }
public override void Decompile(MethodDef method, ITextOutput output, DecompilationContext ctx) { WriteCommentBegin(output, true); output.Write("Method: ", TextTokenKind.Comment); output.WriteDefinition(IdentifierEscaper.Escape(method.FullName), method, TextTokenKind.Comment, false); WriteCommentEnd(output, true); output.WriteLine(); if (!method.HasBody) { return; } StartKeywordBlock(output, ".body", method); ILAstBuilder astBuilder = new ILAstBuilder(); ILBlock ilMethod = new ILBlock(); DecompilerContext context = new DecompilerContext(method.Module) { CurrentType = method.DeclaringType, CurrentMethod = method }; ilMethod.Body = astBuilder.Build(method, inlineVariables, context); if (abortBeforeStep != null) { new ILAstOptimizer().Optimize(context, ilMethod, abortBeforeStep.Value); } if (context.CurrentMethodIsAsync) { output.Write("async", TextTokenKind.Keyword); output.Write("/", TextTokenKind.Operator); output.WriteLine("await", TextTokenKind.Keyword); } var allVariables = ilMethod.GetSelfAndChildrenRecursive <ILExpression>().Select(e => e.Operand as ILVariable) .Where(v => v != null && !v.IsParameter).Distinct(); foreach (ILVariable v in allVariables) { output.WriteDefinition(IdentifierEscaper.Escape(v.Name), v, v.IsParameter ? TextTokenKind.Parameter : TextTokenKind.Local); if (v.Type != null) { output.WriteSpace(); output.Write(":", TextTokenKind.Operator); output.WriteSpace(); if (v.IsPinned) { output.Write("pinned", TextTokenKind.Keyword); output.WriteSpace(); } v.Type.WriteTo(output, ILNameSyntax.ShortTypeName); } if (v.GeneratedByDecompiler) { output.WriteSpace(); output.Write("[", TextTokenKind.Operator); output.Write("generated", TextTokenKind.Keyword); output.Write("]", TextTokenKind.Operator); } output.WriteLine(); } var memberMapping = new MemberMapping(method); foreach (ILNode node in ilMethod.Body) { node.WriteTo(output, memberMapping); if (!node.WritesNewLine) { output.WriteLine(); } } output.AddDebugSymbols(memberMapping); EndKeywordBlock(output); }
// The if statements are resolved so now lets try to build case statements out of them public void DetectSwitchFromIfStatements(ILBlock method) { }