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"), TextTokenType.Comment); output.WriteLine(string.Format("// Code Size: {0} (0x{0:X}) {1}", codeSize, codeSize == 1 ? "byte" : "bytes"), 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(); 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() { 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, method); output.WriteLine(); } } } } }
public ILStructure(CilBody body) : this(ILStructureType.Root, 0, body.GetCodeSize()) { // Build the tree of exception structures: for (int i = 0; i < body.ExceptionHandlers.Count; i++) { ExceptionHandler eh = body.ExceptionHandlers[i]; if (!body.ExceptionHandlers.Take(i).Any(oldEh => oldEh.TryStart == eh.TryStart && oldEh.TryEnd == eh.TryEnd)) { AddNestedStructure(new ILStructure(ILStructureType.Try, (int)eh.TryStart.Offset, (int)eh.TryEnd.Offset, eh)); } if (eh.HandlerType == ExceptionHandlerType.Filter) { AddNestedStructure(new ILStructure(ILStructureType.Filter, (int)eh.FilterStart.Offset, (int)eh.HandlerStart.Offset, eh)); } AddNestedStructure(new ILStructure(ILStructureType.Handler, (int)eh.HandlerStart.Offset, eh.HandlerEnd == null ? body.GetCodeSize() : (int)eh.HandlerEnd.Offset, eh)); } // Very simple loop detection: look for backward branches List <KeyValuePair <Instruction, Instruction> > allBranches = FindAllBranches(body); // We go through the branches in reverse so that we find the biggest possible loop boundary first (think loops with "continue;") for (int i = allBranches.Count - 1; i >= 0; i--) { int loopEnd = allBranches[i].Key.GetEndOffset(); int loopStart = (int)allBranches[i].Value.Offset; if (loopStart < loopEnd) { // We found a backward branch. This is a potential loop. // Check that is has only one entry point: Instruction entryPoint = null; // entry point is first instruction in loop if prev inst isn't an unconditional branch Instruction prev = body.GetPrevious(allBranches[i].Value); if (prev != null && !OpCodeInfo.IsUnconditionalBranch(prev.OpCode)) { entryPoint = allBranches[i].Value; } bool multipleEntryPoints = false; foreach (var pair in allBranches) { if (pair.Key.Offset < loopStart || pair.Key.Offset >= loopEnd) { if (loopStart <= pair.Value.Offset && pair.Value.Offset < loopEnd) { // jump from outside the loop into the loop if (entryPoint == null) { entryPoint = pair.Value; } else if (pair.Value != entryPoint) { multipleEntryPoints = true; } } } } if (!multipleEntryPoints) { AddNestedStructure(new ILStructure(ILStructureType.Loop, loopStart, loopEnd, entryPoint)); } } } SortChildren(); }
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 Disassemble(MethodDef method, CilBody body, MemberMapping methodMapping) { // start writing IL code output.WriteLineComment("// Method Token is 0x{0:x8}", method.MDToken.Raw); output.WriteLineComment("// Method begins at RVA 0x{0:x}", method.RVA); output.WriteLineComment("// Code size {0} (0x{0:x})", body.GetCodeSize()); output.WriteKeyword(".maxstack "); output.WriteLiteral(body.MaxStack.ToString()); output.WriteLine(); if (method.DeclaringType.Module.Assembly != null && method.DeclaringType.Module.EntryPoint == method) { output.WriteKeyword(".entrypoint"); output.WriteLine(); } if (method.Body.HasVariables) { output.WriteKeyword(".locals "); if (method.Body.InitLocals) { output.WriteKeyword("init "); } output.WriteLine("("); output.Indent(); foreach (var v in method.Body.Variables) { output.WriteDefinition("[" + v.Index + "]", v, true); output.Write(" "); v.Type.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]; var branchTargets = GetBranchTargets(body.Instructions); WriteStructureBody(method, body, new ILStructure(body), branchTargets, ref inst, methodMapping, method.Body.GetCodeSize()); } else { foreach (var inst in method.Body.Instructions) { var startLocation = output.Location; inst.WriteTo(method, body, output); if (methodMapping != null) { var next = inst.GetNext(body); // 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 = next == null ? method.Body.GetCodeSize() : next.Offset }, MemberMapping = methodMapping }); } output.WriteLine(); } if (method.Body.HasExceptionHandlers) { output.WriteLine(); foreach (var eh in method.Body.ExceptionHandlers) { eh.WriteTo(output); output.WriteLine(); } } } }