Example #1
0
        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());
        }
Example #2
0
        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);
                }
            }
        }
Example #3
0
        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);
                }
            }
        }
Example #4
0
        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;
            }
        }