HashSet<ILVariable> localVariablesToDefine = new HashSet<ILVariable>(); // local variables that are missing a definition
		
		/// <summary>
		/// Creates the body for the method definition.
		/// </summary>
		/// <param name="methodDef">Method definition to decompile.</param>
		/// <param name="context">Decompilation context.</param>
		/// <param name="parameters">Parameter declarations of the method being decompiled.
		/// These are used to update the parameter names when the decompiler generates names for the parameters.</param>
		/// <returns>Block for the method body</returns>
		public static BlockStatement CreateMethodBody(MethodDef methodDef,
		                                              DecompilerContext context,
		                                              IEnumerable<ParameterDeclaration> parameters,
													  out MemberMapping mm)
		{
			MethodDef oldCurrentMethod = context.CurrentMethod;
			Debug.Assert(oldCurrentMethod == null || oldCurrentMethod == methodDef);
			context.CurrentMethod = methodDef;
			context.CurrentMethodIsAsync = false;
			try {
				AstMethodBodyBuilder builder = new AstMethodBodyBuilder();
				builder.methodDef = methodDef;
				builder.context = context;
				builder.corLib = methodDef.Module.CorLibTypes;
				if (Debugger.IsAttached) {
					return builder.CreateMethodBody(parameters, out mm);
				} else {
					try {
						return builder.CreateMethodBody(parameters, out mm);
					} catch (OperationCanceledException) {
						throw;
					} catch (Exception ex) {
						throw new ICSharpCode.Decompiler.DecompilerException(methodDef, ex);
					}
				}
			} finally {
				context.CurrentMethod = oldCurrentMethod;
			}
		}
		BlockStatement CreateMethodBody(IEnumerable<ParameterDeclaration> parameters, out MemberMapping mm)
		{
			if (methodDef.Body == null) {
				mm = null;
				return null;
			}
			
			context.CancellationToken.ThrowIfCancellationRequested();
			ILBlock ilMethod = new ILBlock();
			ILAstBuilder astBuilder = new ILAstBuilder();
			ilMethod.Body = astBuilder.Build(methodDef, true, context);
			
			context.CancellationToken.ThrowIfCancellationRequested();
			ILAstOptimizer bodyGraph = new ILAstOptimizer();
			bodyGraph.Optimize(context, ilMethod);
			context.CancellationToken.ThrowIfCancellationRequested();
			
			var localVariables = 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, localVariables, ilMethod);
			
			if (parameters != null) {
				foreach (var pair in (from p in parameters
				                      join v in astBuilder.Parameters on p.Annotation<Parameter>() equals v.OriginalParameter
				                      select new { p, v.Name }))
				{
					pair.p.NameToken = Identifier.Create(pair.Name).WithAnnotation(TextTokenKind.Parameter);
				}
			}
			
			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").WithAnnotation(TextTokenKind.Keyword);
				else
					type = AstBuilder.ConvertType(v.Type);
				var newVarDecl = new VariableDeclarationStatement(v.IsParameter ? TextTokenKind.Parameter : TextTokenKind.Local, type, v.Name);
				newVarDecl.Variables.Single().AddAnnotation(v);
				astBlock.Statements.InsertBefore(insertionPoint, newVarDecl);
			}

			mm = new MemberMapping(methodDef, localVariables.ToList());
			
			return astBlock;
		}
		public void StartNode(AstNode node) {
//			var ranges = node.Annotation<List<ILRange>>();
//			if (ranges != null && ranges.Count > 0)
//			{
//				// find the ancestor that has method mapping as annotation
//				if (node.Ancestors != null && node.Ancestors.Count() > 0)
//				{
//					var n = node.Ancestors.FirstOrDefault(a => a.Annotation<MemberMapping>() != null);
//					if (n != null) {
//						MemberMapping mapping = n.Annotation<MemberMapping>();
//
//						// add all ranges
//						foreach (var range in ranges) {
//							mapping.MemberCodeMappings.Add(new SourceCodeMapping {
//							                               	ILInstructionOffset = range,
//							                               	SourceCodeLine = output.CurrentLine,
//							                               	MemberMapping = mapping
//							                               });
//						}
//					}
//				}
//			}

			nodeStack.Push(node);

			MemberMapping mapping = node.Annotation<MemberMapping>();
			if (mapping != null) {
				parentMemberMappings.Push(currentMemberMapping);
				currentMemberMapping = mapping;
			}
			// For ctor/cctor field initializers
			var mms = node.Annotation<List<Tuple<MemberMapping, List<ILRange>>>>();
			if (mms != null) {
				Debug.Assert(multiMappings == null);
				multiMappings = mms;
			}
		}
Beispiel #4
0
        /// <summary>
        /// Gets a mapping given a type, a token and an IL offset.
        /// </summary>
        /// <param name="codeMappings">Code mappings storage.</param>
        /// <param name="ilOffset">IL offset.</param>
        /// <param name="isMatch">True, if perfect match.</param>
        /// <returns>A code mapping.</returns>
        public static SourceCodeMapping GetInstructionByOffset(
            this MemberMapping codeMapping,
            uint ilOffset,
            out bool isMatch)
        {
            isMatch = false;

            if (codeMapping == null)
            {
                throw new ArgumentNullException("CodeMappings storage must be valid!");
            }

            // try find an exact match
            var map = codeMapping.MemberCodeMappings.Find(m => m.ILRange.From <= ilOffset && ilOffset < m.ILRange.To);

            isMatch = map != null;
            if (map == null)
            {
                // get the immediate next one
                map = codeMapping.MemberCodeMappings.Find(m => m.ILRange.From > ilOffset);
            }

            return(map);
        }
Beispiel #5
0
 public SourceCodeMapping(ILRange ilRange, TextPosition start, TextPosition end, MemberMapping mapping)
 {
     this.ilRange = ilRange;
     this.startPos = start;
     this.endPos = end;
     this.memberMapping = mapping;
 }
Beispiel #6
0
 void ITextOutput.AddDebugSymbols(MemberMapping methodDebugSymbols)
 {
 }
Beispiel #7
0
 void ITextOutput.AddDebugSymbols(MemberMapping methodDebugSymbols)
 {
 }
		public void AddDebugSymbols(MemberMapping methodDebugSymbols) {
			DebuggerMemberMappings.Add(methodDebugSymbols);
		}
Beispiel #9
0
		public override void EndNode(AstNode node)
		{
			if (nodeStack.Pop() != node)
				throw new InvalidOperationException();
			
			if (node.Annotation<MemberMapping>() != null) {
				output.AddDebugSymbols(currentMemberMapping);
				currentMemberMapping = parentMemberMappings.Pop();
			}
			var mms = node.Annotation<List<Tuple<MemberMapping, List<ILRange>>>>();
			if (mms != null) {
				Debug.Assert(mms == multiMappings);
				if (mms == multiMappings) {
					foreach (var mm in mms)
						output.AddDebugSymbols(mm.Item1);
					multiMappings = null;
				}
			}
		}
Beispiel #10
0
		public override void StartNode(AstNode node)
		{
			if (nodeStack.Count == 0) {
				if (IsUsingDeclaration(node)) {
					firstUsingDeclaration = !IsUsingDeclaration(node.PrevSibling);
					lastUsingDeclaration = !IsUsingDeclaration(node.NextSibling);
				} else {
					firstUsingDeclaration = false;
					lastUsingDeclaration = false;
				}
			}
			nodeStack.Push(node);
			
			MemberMapping mapping = node.Annotation<MemberMapping>();
			if (mapping != null) {
				parentMemberMappings.Push(currentMemberMapping);
				currentMemberMapping = mapping;
			}
			// For ctor/cctor field initializers
			var mms = node.Annotation<List<Tuple<MemberMapping, List<ILRange>>>>();
			if (mms != null) {
				Debug.Assert(multiMappings == null);
				multiMappings = mms;
			}
		}
Beispiel #11
0
 public SourceCodeMapping(ILRange ilRange, TextPosition start, TextPosition end, MemberMapping mapping)
 {
     this.ilRange       = ilRange;
     this.startPos      = start;
     this.endPos        = end;
     this.memberMapping = mapping;
 }
		public void Disassemble(MethodDef method, MemberMapping debugSymbols)
		{
			// start writing IL code
			CilBody body = method.Body;
			uint codeSize = (uint)body.GetCodeSize();
			uint rva = (uint)method.RVA;
			long offset = method.Module.ToFileOffset(rva);

			if (options.ShowTokenAndRvaComments) {
				output.WriteLine(string.Format("// Header Size: {0} {1}", method.Body.HeaderSize, method.Body.HeaderSize == 1 ? "byte" : "bytes"), TextTokenKind.Comment);
				output.WriteLine(string.Format("// Code Size: {0} (0x{0:X}) {1}", codeSize, codeSize == 1 ? "byte" : "bytes"), TextTokenKind.Comment);
				if (body.LocalVarSigTok != 0) {
					output.Write("// LocalVarSig Token: ", TextTokenKind.Comment);
					output.WriteReference(string.Format("0x{0:X8}", body.LocalVarSigTok), new TokenReference(method.Module, body.LocalVarSigTok), TextTokenKind.Comment, false);
					output.Write(string.Format(" RID: {0}", body.LocalVarSigTok & 0xFFFFFF), TextTokenKind.Comment);
					output.WriteLine();
				}
			}
			output.Write(".maxstack", TextTokenKind.ILDirective);
			output.WriteSpace();
			output.WriteLine(string.Format("{0}", body.MaxStack), TextTokenKind.Number);
            if (method.DeclaringType.Module.EntryPoint == method)
                output.WriteLine (".entrypoint", TextTokenKind.ILDirective);
			
			if (method.Body.HasVariables) {
				output.Write(".locals", TextTokenKind.ILDirective);
				output.WriteSpace();
				if (method.Body.InitLocals) {
					output.Write("init", TextTokenKind.Keyword);
					output.WriteSpace();
				}
				output.WriteLine("(", TextTokenKind.Operator);
				output.Indent();
				foreach (var v in method.Body.Variables) {
					output.Write("[", TextTokenKind.Operator);
					output.WriteDefinition(v.Index.ToString(), v, TextTokenKind.Number);
					output.Write("]", TextTokenKind.Operator);
					output.WriteSpace();
					v.Type.WriteTo(output);
					if (!string.IsNullOrEmpty(v.Name)) {
						output.WriteSpace();
						output.Write(DisassemblerHelpers.Escape(v.Name), TextTokenKind.Local);
					}
					if (v.Index + 1 < method.Body.Variables.Count)
						output.Write(",", TextTokenKind.Operator);
					output.WriteLine();
				}
				output.Unindent();
				output.WriteLine(")", TextTokenKind.Operator);
			}
			output.WriteLine();

			uint baseRva = rva == 0 ? 0 : rva + method.Body.HeaderSize;
			long baseOffs = baseRva == 0 ? 0 : method.Module.ToFileOffset(baseRva);
			using (var byteReader = !options.ShowILBytes || options.CreateInstructionBytesReader == null ? null : options.CreateInstructionBytesReader(method)) {
				if (detectControlStructure && body.Instructions.Count > 0) {
					int index = 0;
					HashSet<uint> branchTargets = GetBranchTargets(body.Instructions);
					WriteStructureBody(body, new ILStructure(body), branchTargets, ref index, debugSymbols, method.Body.GetCodeSize(), baseRva, baseOffs, byteReader, method);
				}
				else {
					var instructions = method.Body.Instructions;
					for (int i = 0; i < instructions.Count; i++) {
						var inst = instructions[i];
						var startLocation = output.Location;
						inst.WriteTo(output, options, baseRva, baseOffs, byteReader, method);

						if (debugSymbols != null) {
							// add IL code mappings - used in debugger
							var next = i + 1 < instructions.Count ? instructions[i + 1] : null;
							debugSymbols.MemberCodeMappings.Add(new SourceCodeMapping(new ILRange(inst.Offset, next == null ? (uint)method.Body.GetCodeSize() : next.Offset), output.Location, output.Location, debugSymbols));
						}

						output.WriteLine();
					}
					if (method.Body.HasExceptionHandlers) {
						output.WriteLine();
						foreach (var eh in method.Body.ExceptionHandlers) {
							eh.WriteTo(output, method);
							output.WriteLine();
						}
					}
				}
			}
		}
		void WriteStructureBody(CilBody body, ILStructure s, HashSet<uint> branchTargets, ref int index, MemberMapping debugSymbols, int codeSize, uint baseRva, long baseOffs, IInstructionBytesReader byteReader, MethodDef method)
		{
			bool isFirstInstructionInStructure = true;
			bool prevInstructionWasBranch = false;
			int childIndex = 0;
			var instructions = body.Instructions;
			while (index < instructions.Count) {
				Instruction inst = instructions[index];
				if (inst.Offset >= s.EndOffset)
					break;
				uint offset = inst.Offset;
				if (childIndex < s.Children.Count && s.Children[childIndex].StartOffset <= offset && offset < s.Children[childIndex].EndOffset) {
					ILStructure child = s.Children[childIndex++];
					WriteStructureHeader(child);
					WriteStructureBody(body, child, branchTargets, ref index, debugSymbols, codeSize, baseRva, baseOffs, byteReader, method);
					WriteStructureFooter(child);
				} else {
					if (!isFirstInstructionInStructure && (prevInstructionWasBranch || branchTargets.Contains(offset))) {
						output.WriteLine(); // put an empty line after branches, and in front of branch targets
					}
					var startLocation = output.Location;
					inst.WriteTo(output, options, baseRva, baseOffs, byteReader, method);
					
					// add IL code mappings - used in debugger
					if (debugSymbols != null) {
						var next = index + 1 < instructions.Count ? instructions[index + 1] : null;
						debugSymbols.MemberCodeMappings.Add(new SourceCodeMapping(new ILRange(inst.Offset, next == null ? (uint)codeSize : next.Offset), startLocation, output.Location, debugSymbols));
					}
					
					output.WriteLine();
					
					prevInstructionWasBranch = inst.OpCode.FlowControl == FlowControl.Branch
						|| inst.OpCode.FlowControl == FlowControl.Cond_Branch
						|| inst.OpCode.FlowControl == FlowControl.Return
						|| inst.OpCode.FlowControl == FlowControl.Throw;
					
					index++;
				}
				isFirstInstructionInStructure = false;
			}
		}