Ejemplo n.º 1
0
        /// <summary>
        /// Dumps disassembly and register liveness
        /// </summary>
        internal override void DumpDisasm(RuntimeFunction rtf, int imageOffset, XmlNode parentNode)
        {
            int rtfOffset  = 0;
            int codeOffset = rtf.CodeOffset;

            while (rtfOffset < rtf.Size)
            {
                string instr;
                int    instrSize = _disassembler.GetInstruction(rtf, imageOffset, rtfOffset, out instr);

                AddXMLNode("offset" + codeOffset, instr, parentNode, $"{codeOffset}");

                if (rtf.Method.GcInfo != null && rtf.Method.GcInfo.Transitions.ContainsKey(codeOffset))
                {
                    foreach (BaseGcTransition transition in rtf.Method.GcInfo.Transitions[codeOffset])
                    {
                        AddXMLNode("Transition", transition.ToString(), parentNode, $"{codeOffset}");
                    }
                }

                CoreDisTools.ClearOutputBuffer();
                rtfOffset  += instrSize;
                codeOffset += instrSize;
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Dumps disassembly and register liveness
        /// </summary>
        internal override void DumpDisasm(RuntimeFunction rtf, int imageOffset)
        {
            int    indent       = (_options.Naked ? 11 : 32);
            string indentString = new string(' ', indent);
            int    rtfOffset    = 0;
            int    codeOffset   = rtf.CodeOffset;

            while (rtfOffset < rtf.Size)
            {
                string instr;
                int    instrSize = _disassembler.GetInstruction(rtf, imageOffset, rtfOffset, out instr);

                if (_r2r.Machine == Machine.Amd64 && ((ILCompiler.Reflection.ReadyToRun.Amd64.UnwindInfo)rtf.UnwindInfo).UnwindCodes.ContainsKey(codeOffset))
                {
                    List <ILCompiler.Reflection.ReadyToRun.Amd64.UnwindCode> codes = ((ILCompiler.Reflection.ReadyToRun.Amd64.UnwindInfo)rtf.UnwindInfo).UnwindCodes[codeOffset];
                    foreach (ILCompiler.Reflection.ReadyToRun.Amd64.UnwindCode code in codes)
                    {
                        _writer.Write($"{indentString}{code.UnwindOp} {code.OpInfoStr}");
                        if (code.NextFrameOffset != -1)
                        {
                            _writer.WriteLine($"{indentString}{code.NextFrameOffset}");
                        }
                        _writer.WriteLine();
                    }
                }

                if (rtf.Method.GcInfo?.Transitions != null && rtf.Method.GcInfo.Transitions.ContainsKey(codeOffset))
                {
                    foreach (BaseGcTransition transition in rtf.Method.GcInfo.Transitions[codeOffset])
                    {
                        _writer.WriteLine($"{indentString}{transition}");
                    }
                }

                /* According to https://msdn.microsoft.com/en-us/library/ck9asaa9.aspx and src/vm/gcinfodecoder.cpp
                 * UnwindCode and GcTransition CodeOffsets are encoded with a -1 adjustment (that is, it's the offset of the start of the next instruction)
                 */
                _writer.Write(instr);

                CoreDisTools.ClearOutputBuffer();
                rtfOffset  += instrSize;
                codeOffset += instrSize;
            }
        }
Ejemplo n.º 3
0
        internal unsafe override void DumpDisasm(IntPtr Disasm, RuntimeFunction rtf, int imageOffset, byte[] image, XmlNode parentNode = null)
        {
            int rtfOffset  = 0;
            int codeOffset = rtf.CodeOffset;

            while (rtfOffset < rtf.Size)
            {
                string instr;
                int    instrSize = CoreDisTools.GetInstruction(Disasm, rtf, imageOffset, rtfOffset, image, out instr);

                _writer.Write(instr);
                if (rtf.Method.GcInfo != null && rtf.Method.GcInfo.Transitions.ContainsKey(codeOffset))
                {
                    _writer.WriteLine($"\t\t\t\t{rtf.Method.GcInfo.Transitions[codeOffset].GetSlotState(rtf.Method.GcInfo.SlotTable)}");
                }

                CoreDisTools.ClearOutputBuffer();
                rtfOffset  += instrSize;
                codeOffset += instrSize;
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Dumps disassembly and register liveness
        /// </summary>
        internal override void DumpDisasm(RuntimeFunction rtf, int imageOffset, XmlNode parentNode = null)
        {
            int rtfOffset  = 0;
            int codeOffset = rtf.CodeOffset;

            while (rtfOffset < rtf.Size)
            {
                string instr;
                int    instrSize = _disassembler.GetInstruction(rtf, imageOffset, rtfOffset, out instr);

                _writer.Write(instr);

                if (_r2r.Machine == Machine.Amd64 && ((Amd64.UnwindInfo)rtf.UnwindInfo).UnwindCodes.ContainsKey(codeOffset))
                {
                    List <Amd64.UnwindCode> codes = ((Amd64.UnwindInfo)rtf.UnwindInfo).UnwindCodes[codeOffset];
                    foreach (Amd64.UnwindCode code in codes)
                    {
                        _writer.Write($"\t\t\t\t{code.UnwindOp} {code.OpInfoStr}");
                        if (code.NextFrameOffset != -1)
                        {
                            _writer.WriteLine($" - {code.NextFrameOffset}");
                        }
                        _writer.WriteLine();
                    }
                }

                if (rtf.Method.GcInfo != null && rtf.Method.GcInfo.Transitions.ContainsKey(codeOffset))
                {
                    foreach (BaseGcTransition transition in rtf.Method.GcInfo.Transitions[codeOffset])
                    {
                        _writer.WriteLine($"\t\t\t\t{transition.ToString()}");
                    }
                }

                CoreDisTools.ClearOutputBuffer();
                rtfOffset  += instrSize;
                codeOffset += instrSize;
            }
        }
Ejemplo n.º 5
0
        internal unsafe override void DumpDisasm(IntPtr Disasm, RuntimeFunction rtf, int imageOffset, byte[] image, XmlNode parentNode)
        {
            int rtfOffset  = 0;
            int codeOffset = rtf.CodeOffset;
            Dictionary <int, GcInfo.GcTransition> transitions = rtf.Method.GcInfo.Transitions;
            GcSlotTable slotTable = rtf.Method.GcInfo.SlotTable;

            while (rtfOffset < rtf.Size)
            {
                string instr;
                int    instrSize = CoreDisTools.GetInstruction(Disasm, rtf, imageOffset, rtfOffset, image, out instr);

                AddXMLNode("offset" + codeOffset, instr, parentNode, $"{codeOffset}");
                if (transitions.ContainsKey(codeOffset))
                {
                    AddXMLNode("Transition", transitions[codeOffset].GetSlotState(slotTable), parentNode, $"{codeOffset}");
                }

                CoreDisTools.ClearOutputBuffer();
                rtfOffset  += instrSize;
                codeOffset += instrSize;
            }
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Dumps disassembly and register liveness
        /// </summary>
        internal override void DumpDisasm(RuntimeFunction rtf, int imageOffset, XmlNode parentNode = null)
        {
            int rtfOffset  = 0;
            int codeOffset = rtf.CodeOffset;

            while (rtfOffset < rtf.Size)
            {
                string instr;
                int    instrSize = _disassembler.GetInstruction(rtf, imageOffset, rtfOffset, out instr);

                _writer.Write(instr);
                if (rtf.Method.GcInfo != null && rtf.Method.GcInfo.Transitions.ContainsKey(codeOffset))
                {
                    foreach (BaseGcTransition transition in rtf.Method.GcInfo.Transitions[codeOffset])
                    {
                        _writer.WriteLine($"\t\t\t\t{transition.ToString()}");
                    }
                }

                CoreDisTools.ClearOutputBuffer();
                rtfOffset  += instrSize;
                codeOffset += instrSize;
            }
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Parse a single instruction and return the RVA of the next instruction.
        /// </summary>
        /// <param name="rtf">Runtime function to parse</param>
        /// <param name="imageOffset">Offset within the PE image byte array</param>
        /// <param name="rtfOffset">Instruction offset within the runtime function</param>
        /// <param name="instruction">Output text representation of the instruction</param>
        /// <returns>Instruction size in bytes - i.o.w. the next instruction starts at rtfOffset + (the return value)</returns>
        public int GetInstruction(RuntimeFunction rtf, int imageOffset, int rtfOffset, out string instruction)
        {
            if (_disasm == IntPtr.Zero)
            {
                instruction = "";
                return(rtf.Size);
            }

            int instrSize = CoreDisTools.GetInstruction(_disasm, rtf, imageOffset, rtfOffset, _reader.Image, out instruction);

            CoreDisTools.ClearOutputBuffer();

            instruction = instruction.Replace('\t', ' ');

            if (_options.Naked)
            {
                StringBuilder nakedInstruction = new StringBuilder();
                foreach (string line in instruction.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries))
                {
                    int colon = line.IndexOf(':');
                    if (colon >= 0)
                    {
                        colon += 2;
                        while (colon + 3 <= line.Length &&
                               IsXDigit(line[colon]) &&
                               IsXDigit(line[colon + 1]) &&
                               line[colon + 2] == ' ')
                        {
                            colon += 3;
                        }

                        if (!_options.HideOffsets)
                        {
                            nakedInstruction.Append($"{(rtfOffset + rtf.CodeOffset),8:x4}:");
                            nakedInstruction.Append("  ");
                        }
                        else
                        {
                            nakedInstruction.Append("    ");
                        }
                        nakedInstruction.Append(line.Substring(colon).TrimStart());
                        nakedInstruction.Append('\n');
                    }
                    else
                    {
                        nakedInstruction.Append(' ', 7);
                        nakedInstruction.Append(line.TrimStart());
                        nakedInstruction.Append('\n');
                    }
                }
                instruction = nakedInstruction.ToString();
            }

            switch (_reader.Machine)
            {
            case Machine.Amd64:
                ProbeX64Quirks(rtf, imageOffset, rtfOffset, instrSize, ref instruction);
                break;

            case Machine.I386:
                ProbeX86Quirks(rtf, imageOffset, rtfOffset, instrSize, ref instruction);
                break;

            case Machine.ArmThumb2:
            case Machine.Thumb:
                break;

            case Machine.Arm64:
                break;

            default:
                throw new NotImplementedException();
            }

            instruction = instruction.Replace("\n", Environment.NewLine);
            return(instrSize);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Parse and dump a single instruction and return its size in bytes.
        /// </summary>
        /// <param name="rtf">Runtime function to parse</param>
        /// <param name="imageOffset">Offset within the PE image byte array</param>
        /// <param name="rtfOffset">Instruction offset within the runtime function</param>
        /// <param name="instruction">Output text representation of the instruction</param>
        /// <returns>Instruction size in bytes - i.o.w. the next instruction starts at rtfOffset + (the return value)</returns>
        public int GetInstruction(RuntimeFunction rtf, int imageOffset, int rtfOffset, out string instruction)
        {
            if (_disasm == IntPtr.Zero)
            {
                instruction = "";
                return(rtf.Size);
            }

            int instrSize = CoreDisTools.GetInstruction(_disasm, rtf, imageOffset, rtfOffset, _reader.Image, out instruction);

            CoreDisTools.ClearOutputBuffer();

            // CoreDisTools dumps instructions in the following format:
            //
            //      address: bytes [padding] \t mnemonic [\t operands] \n
            //
            // However, due to an LLVM issue regarding instruction prefixes (https://bugs.llvm.org/show_bug.cgi?id=7709),
            // multiple lines may be returned for a single x86/x64 instruction.

            var builder = new StringBuilder();
            int lineNum = 0;
            // The start index of the last line in builder
            int lineStartIndex = 0;

            // Remove this foreach wrapper and line* variables after the aforementioned LLVM issue is fixed
            foreach (string line in instruction.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries))
            {
                int colonIndex = line.IndexOf(':');
                int tab1Index  = line.IndexOf('\t');

                if ((0 < colonIndex) && (colonIndex < tab1Index))
                {
                    // First handle the address and the byte dump
                    if (_options.Naked)
                    {
                        if (!_options.HideOffsets)
                        {
                            // All lines but the last one must represent single-byte prefixes, so add lineNum to the offset
                            builder.Append($"{rtf.CodeOffset + rtfOffset + lineNum,8:x4}:");
                        }
                    }
                    else
                    {
                        if (_reader.Machine == Machine.Arm64)
                        {
                            // Replace " hh hh hh hh " byte dump with " hhhhhhhh ".
                            // CoreDisTools should be fixed to dump bytes this way for ARM64.
                            uint instructionBytes = BitConverter.ToUInt32(_reader.Image, imageOffset + rtfOffset);
                            builder.Append(line, 0, colonIndex + 1);
                            builder.Append(' ');
                            builder.Append(instructionBytes.ToString("x8"));
                        }
                        else
                        {
                            // Copy the offset and the byte dump
                            int byteDumpEndIndex = tab1Index;
                            do
                            {
                                byteDumpEndIndex--;
                            }while (line[byteDumpEndIndex] == ' ');
                            builder.Append(line, 0, byteDumpEndIndex + 1);
                        }
                        builder.Append(' ');
                    }

                    // Now handle the mnemonic and operands. Ensure proper indentation for the mnemonic.
                    EnsureIndentation(builder, lineStartIndex, MnemonicIndentation);

                    int tab2Index = line.IndexOf('\t', tab1Index + 1);
                    if (tab2Index >= 0)
                    {
                        // Copy everything between the first and the second tabs
                        builder.Append(line, tab1Index + 1, tab2Index - tab1Index - 1);
                        // Ensure proper indentation for the operands
                        EnsureIndentation(builder, lineStartIndex, OperandsIndentation);
                        int afterTab2Index = tab2Index + 1;

                        // Work around an LLVM issue causing an extra space to be output before operands;
                        // see https://reviews.llvm.org/D35946.
                        if ((afterTab2Index < line.Length) &&
                            ((line[afterTab2Index] == ' ') || (line[afterTab2Index] == '\t')))
                        {
                            afterTab2Index++;
                        }

                        // Copy everything after the second tab
                        int savedLength = builder.Length;
                        builder.Append(line, afterTab2Index, line.Length - afterTab2Index);
                        // There should be no extra tabs. Should we encounter them, replace them with a single space.
                        if (line.IndexOf('\t', afterTab2Index) >= 0)
                        {
                            builder.Replace('\t', ' ', savedLength, builder.Length - savedLength);
                        }
                    }
                    else
                    {
                        // Copy everything after the first tab
                        builder.Append(line, tab1Index + 1, line.Length - tab1Index - 1);
                    }
                }
                else
                {
                    // Should not happen. Just replace tabs with spaces.
                    builder.Append(line.Replace('\t', ' '));
                }

                builder.Append('\n');
                lineNum++;
                lineStartIndex = builder.Length;
            }

            instruction = builder.ToString();

            switch (_reader.Machine)
            {
            case Machine.Amd64:
                ProbeX64Quirks(rtf, imageOffset, rtfOffset, instrSize, ref instruction);
                break;

            case Machine.I386:
                ProbeX86Quirks(rtf, imageOffset, rtfOffset, instrSize, ref instruction);
                break;

            case Machine.ArmThumb2:
                break;

            case Machine.Arm64:
                break;

            default:
                throw new NotImplementedException();
            }

            instruction = instruction.Replace("\n", Environment.NewLine);
            return(instrSize);
        }