public string Copy(IEnumerable <SpanData <ReferenceInfo> > refs, Lazy <IMethodAnnotations> methodAnnotations) { var sb = new StringBuilder(); IInstructionBytesReader reader = null; try { MethodDef method = null; int index = 0; foreach (var r in refs) { var ir = (InstructionReference)r.Data.Reference; var instr = ir.Instruction; if (ir.Method != method) { if (reader != null) { reader.Dispose(); } method = ir.Method; reader = InstructionBytesReader.Create(method, methodAnnotations.Value.IsBodyModified(method)); index = method.Body.Instructions.IndexOf(instr); if (index < 0) { throw new InvalidOperationException(); } reader.SetInstruction(index, instr.Offset); } else if (index >= method.Body.Instructions.Count) { throw new InvalidOperationException(); } else if (method.Body.Instructions[index + 1] != ir.Instruction) { index = method.Body.Instructions.IndexOf(instr); if (index < 0) { throw new InvalidOperationException(); } reader.SetInstruction(index, instr.Offset); } else { index++; } int size = instr.GetSize(); for (int i = 0; i < size; i++) { int b = reader.ReadByte(); if (b < 0) { sb.Append("??"); FoundUnknownBytes = true; } else { sb.Append(string.Format("{0:X2}", b)); } } } } finally { if (reader != null) { reader.Dispose(); } } return(sb.ToString()); }
public static void WriteTo(this Instruction instruction, ITextOutput writer, DisassemblerOptions options, uint baseRva, long baseOffs, IInstructionBytesReader byteReader, MethodDef method) { if (options != null && (options.ShowTokenAndRvaComments || options.ShowILBytes)) { writer.Write("/* ", TextTokenType.Comment); bool needSpace = false; if (options.ShowTokenAndRvaComments) { ulong fileOffset = (ulong)baseOffs + instruction.Offset; writer.WriteReference(string.Format("0x{0:X8}", fileOffset), new AddressReference(options.OwnerModule == null ? null : options.OwnerModule.Location, false, fileOffset, (ulong)instruction.GetSize()), TextTokenType.Comment, false); needSpace = true; } if (options.ShowILBytes) { if (needSpace) writer.Write(' ', TextTokenType.Comment); if (byteReader == null) writer.Write("??", TextTokenType.Comment); else { int size = instruction.GetSize(); for (int i = 0; i < size; i++) { var b = byteReader.ReadByte(); if (b < 0) writer.Write("??", TextTokenType.Comment); else writer.Write(string.Format("{0:X2}", b), TextTokenType.Comment); } // Most instructions should be at most 5 bytes in length, but use 6 since // ldftn/ldvirtftn are 6 bytes long. The longest instructions are those with // 8 byte operands, ldc.i8 and ldc.r8: 9 bytes. const int MIN_BYTES = 6; for (int i = size; i < MIN_BYTES; i++) writer.Write(" ", TextTokenType.Comment); } } writer.Write(" */", TextTokenType.Comment); writer.WriteSpace(); } writer.WriteDefinition(DnlibExtensions.OffsetToString(instruction.GetOffset()), new InstructionReference(method, instruction), TextTokenType.Label, false); writer.Write(':', TextTokenType.Operator); writer.WriteSpace(); writer.WriteReference(instruction.OpCode.Name, instruction.OpCode, TextTokenType.OpCode); if (instruction.Operand != null) { int count = OPERAND_ALIGNMENT - instruction.OpCode.Name.Length; if (count <= 0) count = 1; writer.Write(spaces[count], TextTokenType.Text); if (instruction.OpCode == OpCodes.Ldtoken) { var member = instruction.Operand as IMemberRef; if (member != null && member.IsMethod) { writer.Write("method", TextTokenType.Keyword); writer.WriteSpace(); } else if (member != null && member.IsField) { writer.Write("field", TextTokenType.Keyword); writer.WriteSpace(); } } WriteOperand(writer, instruction.Operand, method); } if (options != null && options.GetOpCodeDocumentation != null) { var doc = options.GetOpCodeDocumentation(instruction.OpCode); if (doc != null) { writer.Write("\t", TextTokenType.Text); writer.Write("// " + doc, TextTokenType.Comment); } } }
public static void WriteTo(this Instruction instruction, ITextOutput writer, DisassemblerOptions options, uint baseRva, long baseOffs, IInstructionBytesReader byteReader, MethodDef method) { if (options != null && (options.ShowTokenAndRvaComments || options.ShowILBytes)) { writer.Write("/* ", TextTokenType.Comment); bool needSpace = false; if (options.ShowTokenAndRvaComments) { ulong fileOffset = (ulong)baseOffs + instruction.Offset; writer.WriteReference(string.Format("0x{0:X8}", fileOffset), new AddressReference(options.OwnerModule == null ? null : options.OwnerModule.Location, false, fileOffset, (ulong)instruction.GetSize()), TextTokenType.Comment, false); needSpace = true; } if (options.ShowILBytes) { if (needSpace) { writer.Write(' ', TextTokenType.Comment); } if (byteReader == null) { writer.Write("??", TextTokenType.Comment); } else { int size = instruction.GetSize(); for (int i = 0; i < size; i++) { var b = byteReader.ReadByte(); if (b < 0) { writer.Write("??", TextTokenType.Comment); } else { writer.Write(string.Format("{0:X2}", b), TextTokenType.Comment); } } // Most instructions should be at most 5 bytes in length, but use 6 since // ldftn/ldvirtftn are 6 bytes long. The longest instructions are those with // 8 byte operands, ldc.i8 and ldc.r8: 9 bytes. const int MIN_BYTES = 6; for (int i = size; i < MIN_BYTES; i++) { writer.Write(" ", TextTokenType.Comment); } } } writer.Write(" */", TextTokenType.Comment); writer.WriteSpace(); } writer.WriteDefinition(DnlibExtensions.OffsetToString(instruction.GetOffset()), new InstructionReference(method, instruction), TextTokenType.Label, false); writer.Write(':', TextTokenType.Operator); writer.WriteSpace(); writer.WriteReference(instruction.OpCode.Name, instruction.OpCode, TextTokenType.OpCode); if (instruction.Operand != null) { int count = OPERAND_ALIGNMENT - instruction.OpCode.Name.Length; if (count <= 0) { count = 1; } writer.Write(spaces[count], TextTokenType.Text); if (instruction.OpCode == OpCodes.Ldtoken) { var member = instruction.Operand as IMemberRef; if (member != null && member.IsMethod) { writer.Write("method", TextTokenType.Keyword); writer.WriteSpace(); } else if (member != null && member.IsField) { writer.Write("field", TextTokenType.Keyword); writer.WriteSpace(); } } WriteOperand(writer, instruction.Operand, method); } if (options != null && options.GetOpCodeDocumentation != null) { var doc = options.GetOpCodeDocumentation(instruction.OpCode); if (doc != null) { writer.Write("\t", TextTokenType.Text); writer.Write("// " + doc, TextTokenType.Comment); } } }
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() { 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; } }
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() { 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; } }