public virtual void AddDebuggerMemberMapping(MemberMapping memberMapping) { if (memberMapping == null) throw new ArgumentNullException("memberMapping"); int token = memberMapping.MetadataToken; codeMappings.Add(token, memberMapping); }
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); if (method.HasOverrides) foreach (var methodOverride in method.Overrides) output.WriteLine(".override {0}::{1}", methodOverride.DeclaringType.FullName, methodOverride.Name); 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); output.Write(' '); output.Write(DisassemblerHelpers.Escape(v.Name)); output.WriteLine(); } output.Unindent(); output.WriteLine(")"); } output.WriteLine(); if (detectControlStructure && body.Instructions.Count > 0) { Instruction inst = body.Instructions[0]; WriteStructureBody(new ILStructure(body), ref inst, methodMapping, method.Body.CodeSize); } else { foreach (var inst in method.Body.Instructions) { inst.WriteTo(output); // 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(); } output.WriteLine(); foreach (var eh in method.Body.ExceptionHandlers) { eh.WriteTo(output); output.WriteLine(); } } }
/// <summary> /// Gets source code mapping and metadata token based on type name and line number. /// </summary> /// <param name="codeMappings">Code mappings storage.</param> /// <param name="typeName">Member reference name.</param> /// <param name="lineNumber">Line number.</param> /// <param name="metadataToken">Metadata token.</param> /// <returns></returns> public static SourceCodeMapping GetInstructionByLineNumber( this MemberMapping codeMapping, int lineNumber, out int metadataToken) { if (codeMapping == null) { throw new ArgumentException("CodeMappings storage must be valid!"); } var map = codeMapping.MemberCodeMappings.Find(m => m.StartLocation.Line == lineNumber); if (map != null) { metadataToken = codeMapping.MetadataToken; return(map); } metadataToken = 0; return(null); }
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; } }
/// <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.ILInstructionOffset.From <= ilOffset && ilOffset < m.ILInstructionOffset.To); isMatch = map != null; if (map == null) { // get the immediate next one map = codeMapping.MemberCodeMappings.Find(m => m.ILInstructionOffset.From > ilOffset); } return(map); }
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; } }
void ITextOutput.AddDebuggerMemberMapping(MemberMapping memberMapping) { }
public void AddDebugSymbols(MemberMapping methodDebugSymbols) { DebuggerMemberMappings.Add(methodDebugSymbols); }
public void AddDebuggerMemberMapping(ICSharpCode.Decompiler.MemberMapping memberMapping) { }
void ITextOutput.AddDebugSymbols(MemberMapping methodDebugSymbols) { }
public void AddDebuggerMemberMapping(MemberMapping memberMapping) { }
public 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); startLocations.Push(output.Location); MemberMapping mapping = node.Annotation<MemberMapping>(); if (mapping != null) { parentMemberMappings.Push(currentMemberMapping); currentMemberMapping = mapping; } }
void WriteStructureBody(ILStructure s, ref Instruction inst, MemberMapping currentMethodMapping, int codeSize) { 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, ref inst, currentMethodMapping, codeSize); WriteStructureFooter(child); } else { 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(); inst = inst.Next; } } }
void WriteStructureBody(CilBody body, ILStructure s, HashSet<uint> branchTargets, ref int index, MemberMapping debugSymbols, int codeSize) { 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); 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.GetOpCodeDocumentation); // 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() { StartLocation = startLocation, EndLocation = output.Location, ILInstructionOffset = new ILRange(inst.Offset, next == null ? (uint)codeSize : next.Offset), MemberMapping = 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; } }
/// <summary> /// Create code mapping for a method. /// </summary> /// <param name="method">Method to create the mapping for.</param> /// <param name="sourceCodeMappings">Source code mapping storage.</param> internal static MemberMapping CreateCodeMapping( this MethodDefinition member, Tuple<string, List<MemberMapping>> codeMappings) { 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.Item1 == member.DeclaringType.FullName) { var mapping = codeMappings.Item2; if (mapping.Find(map => (int)map.MetadataToken == member.MetadataToken.ToInt32()) == null) { currentMemberMapping = new MemberMapping() { MetadataToken = (uint)member.MetadataToken.ToInt32(), MemberReference = member.DeclaringType.Resolve(), MemberCodeMappings = new List<SourceCodeMapping>(), CodeSize = member.Body.CodeSize }; mapping.Add(currentMemberMapping); } } return currentMemberMapping; }
public void Disassemble(MethodDef method, MemberMapping debugSymbols) { // start writing IL code CilBody body = method.Body; uint codeSize = (uint)body.GetCodeSize(); output.WriteLine(string.Format("// RVA 0x{0:x8} - 0x{1:x8} ({2} (0x{2:x}) bytes)", (uint)method.RVA, (uint)method.RVA + codeSize, codeSize), TextTokenType.Comment); output.WriteLine(string.Format("// Metadata token 0x{0:x8} (RID {1})", method.MDToken.ToInt32(), method.Rid), TextTokenType.Comment); if (body.LocalVarSigTok != 0) output.WriteLine(string.Format("// LocalVarSig token 0x{0:x8} (RID {1})", body.LocalVarSigTok, body.LocalVarSigTok & 0xFFFFFF), TextTokenType.Comment); output.Write(".maxstack", TextTokenType.ILDirective); output.WriteSpace(); output.WriteLine(string.Format("{0}", body.MaxStack), TextTokenType.Number); if (method.DeclaringType.Module.EntryPoint == method) output.WriteLine (".entrypoint", TextTokenType.ILDirective); if (method.Body.HasVariables) { output.Write(".locals", TextTokenType.ILDirective); output.WriteSpace(); if (method.Body.InitLocals) { output.Write("init", TextTokenType.Keyword); output.WriteSpace(); } output.WriteLine("(", TextTokenType.Operator); output.Indent(); foreach (var v in method.Body.Variables) { output.Write('[', TextTokenType.Operator); output.WriteDefinition(v.Index.ToString(), v, TextTokenType.Number); output.Write(']', TextTokenType.Operator); output.WriteSpace(); v.Type.WriteTo(output); if (!string.IsNullOrEmpty(v.Name)) { output.WriteSpace(); output.Write(DisassemblerHelpers.Escape(v.Name), TextTokenType.Local); } if (v.Index + 1 < method.Body.Variables.Count) output.Write(',', TextTokenType.Operator); output.WriteLine(); } output.Unindent(); output.WriteLine(")", TextTokenType.Operator); } output.WriteLine(); 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()); } 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.GetOpCodeDocumentation); 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() { StartLocation = output.Location, EndLocation = output.Location, ILInstructionOffset = new ILRange(inst.Offset, next == null ? (uint)method.Body.GetCodeSize() : next.Offset), MemberMapping = debugSymbols }); } output.WriteLine(); } if (method.Body.HasExceptionHandlers) { output.WriteLine(); foreach (var eh in method.Body.ExceptionHandlers) { eh.WriteTo(output); output.WriteLine(); } } } }
public void AddDebuggerMemberMapping(MemberMapping memberMapping) { throw new NotImplementedException(); }
public 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); startLocations.Push(output.Location); if (node is EntityDeclaration && node.Annotation<MemberReference>() != null && node.GetChildByRole(Roles.Identifier).IsNull) output.WriteDefinition("", node.Annotation<MemberReference>(), false); MemberMapping mapping = node.Annotation<MemberMapping>(); if (mapping != null) { parentMemberMappings.Push(currentMemberMapping); currentMemberMapping = mapping; } }
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; } } }
public void EndNode(AstNode node) { if (nodeStack.Pop() != node) throw new InvalidOperationException(); var startLocation = startLocations.Pop(); // code mappings if (currentMemberMapping != null) { var ranges = node.Annotation<List<ILRange>>(); if (ranges != null && ranges.Count > 0) { // add all ranges foreach (var range in ranges) { currentMemberMapping.MemberCodeMappings.Add( new SourceCodeMapping { ILInstructionOffset = range, StartLocation = startLocation, EndLocation = output.Location, MemberMapping = currentMemberMapping }); } } } if (node.Annotation<MemberMapping>() != null) { output.AddDebuggerMemberMapping(currentMemberMapping); currentMemberMapping = parentMemberMappings.Pop(); } }
public void StartNode(AstNode node) { this.nodes.Push(node); if (this.highlightItems.Count > 0) { this.startLocations.Push(this.CurrentLocation); MemberMapping mapping = node.Annotation<MemberMapping>(); if (mapping != null) { this.memberMapping.Push(this.currentMapping); this.currentMapping = mapping; } } }
public void AddDebuggerMemberMapping(MemberMapping memberMapping) { DebuggerMemberMappings.Add(memberMapping); output.AddDebuggerMemberMapping(memberMapping); }
/// <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.Find(map => map.MetadataToken == member.MetadataToken.ToInt32()) == null) { currentMemberMapping = new MemberMapping() { MetadataToken = member.MetadataToken.ToInt32(), MemberCodeMappings = new List<SourceCodeMapping>(), MemberReference = actualMemberReference ?? member, CodeSize = member.Body.CodeSize }; codeMappings.Add(currentMemberMapping); } return currentMemberMapping; }
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 != null && 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) { var startLocation = output.Location; inst.WriteTo(output); if (methodMapping != null) { // add IL code mappings - used in debugger methodMapping.MemberCodeMappings.Add( new SourceCodeMapping() { StartLocation = output.Location, EndLocation = output.Location, 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(); } } } }
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); }
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; } }
public void EndNode(AstNode node) { this.nodes.Pop(); if (this.highlightItems.Count > 0) { TextLocation startLocation = this.startLocations.Pop(); if (this.currentMapping != null) { var ranges = node.Annotation<List<ICSharpCode.Decompiler.ILAst.ILRange>>(); if ((ranges != null) && (ranges.Count > 0)) { foreach (var range in ranges) { SourceCodeMapping scm = null; //foreach (int offset in this.HighlightOffsets) foreach (HighlightItem item in this.highlightItems) { if ((item.Offset >= range.From) && (item.Offset <= range.To)) { if (this.CheckNode(node, item)) { if (scm == null) { int adjust = 0; if (node is ThrowStatement) { adjust = -(this.indent * tabSize + 2); } scm = new SourceCodeMapping() { ILInstructionOffset = range, StartLocation = startLocation, EndLocation = new TextLocation(this.CurrentLocation.Line, this.CurrentLocation.Column + adjust), MemberMapping = this.currentMapping }; } this.HighlightMapping[item.Offset].Add(scm); } } } this.currentMapping.MemberCodeMappings.Add(scm); } } } if (node.Annotation<MemberMapping>() != null) { this.currentMapping = this.memberMapping.Pop(); } } }