public void Disassemble(MethodBody body, MemberMapping methodMapping) { // start writing IL code MethodDefinition method = body.Method; output.WriteLine("// Method begins at RVA 0x{0:x4}", method.RVA); output.WriteLine("// Code size {0} (0x{0:x})", body.CodeSize); output.WriteLine(".maxstack {0}", body.MaxStackSize); if (method.DeclaringType.Module.Assembly.EntryPoint == method) output.WriteLine (".entrypoint"); if (method.Body.HasVariables) { output.Write(".locals "); if (method.Body.InitLocals) output.Write("init "); output.WriteLine("("); output.Indent(); foreach (var v in method.Body.Variables) { output.WriteDefinition("[" + v.Index + "] ", v); v.VariableType.WriteTo(output); if (!string.IsNullOrEmpty(v.Name)) { output.Write(' '); output.Write(DisassemblerHelpers.Escape(v.Name)); } if (v.Index + 1 < method.Body.Variables.Count) output.Write(','); output.WriteLine(); } output.Unindent(); output.WriteLine(")"); } output.WriteLine(); if (detectControlStructure && body.Instructions.Count > 0) { Instruction inst = body.Instructions[0]; HashSet<int> branchTargets = GetBranchTargets(body.Instructions); WriteStructureBody(new ILStructure(body), branchTargets, ref inst, methodMapping, method.Body.CodeSize); } else { foreach (var inst in method.Body.Instructions) { inst.WriteTo(output); if (methodMapping != null) { // add IL code mappings - used in debugger methodMapping.MemberCodeMappings.Add( new SourceCodeMapping() { SourceCodeLine = output.CurrentLine, ILInstructionOffset = new ILRange { From = inst.Offset, To = inst.Next == null ? method.Body.CodeSize : inst.Next.Offset }, MemberMapping = methodMapping }); } output.WriteLine(); } if (method.Body.HasExceptionHandlers) { output.WriteLine(); foreach (var eh in method.Body.ExceptionHandlers) { eh.WriteTo(output); output.WriteLine(); } } } }
/// <summary> /// Create code mapping for a method. /// </summary> /// <param name="method">Method to create the mapping for.</param> /// <param name="codeMappings">Source code mapping storage.</param> /// <param name="actualMemberReference">The actual member reference.</param> internal static MemberMapping CreateCodeMapping( this MethodDefinition member, List<MemberMapping> codeMappings, MemberReference actualMemberReference = null) { if (member == null || !member.HasBody) return null; if (codeMappings == null) return null; // create IL/CSharp code mappings - used in debugger MemberMapping currentMemberMapping = null; if (codeMappings.Any(map => map.MetadataToken == member.MetadataToken.ToInt32())) { currentMemberMapping = new MemberMapping() { MetadataToken = member.MetadataToken.ToInt32(), MemberCodeMappings = new List<SourceCodeMapping>(), MemberReference = actualMemberReference ?? member, CodeSize = member.Body.CodeSize }; codeMappings.Add(currentMemberMapping); } return currentMemberMapping; }
void WriteStructureBody(ILStructure s, HashSet<int> branchTargets, ref Instruction inst, MemberMapping currentMethodMapping, int codeSize) { bool isFirstInstructionInStructure = true; bool prevInstructionWasBranch = false; int childIndex = 0; while (inst != null && inst.Offset < s.EndOffset) { int 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(child, branchTargets, ref inst, currentMethodMapping, codeSize); WriteStructureFooter(child); } else { if (!isFirstInstructionInStructure && (prevInstructionWasBranch || branchTargets.Contains(offset))) { output.WriteLine(); // put an empty line after branches, and in front of branch targets } inst.WriteTo(output); // add IL code mappings - used in debugger if (currentMethodMapping != null) { currentMethodMapping.MemberCodeMappings.Add( new SourceCodeMapping() { SourceCodeLine = output.CurrentLine, ILInstructionOffset = new ILRange { From = inst.Offset, To = inst.Next == null ? codeSize : inst.Next.Offset }, MemberMapping = currentMethodMapping }); } output.WriteLine(); prevInstructionWasBranch = inst.OpCode.FlowControl == FlowControl.Branch || inst.OpCode.FlowControl == FlowControl.Cond_Branch || inst.OpCode.FlowControl == FlowControl.Return || inst.OpCode.FlowControl == FlowControl.Throw; inst = inst.Next; } isFirstInstructionInStructure = false; } }