/// <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; } }
/// <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; } }
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; } }
/// <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; } }
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; } }
/// <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; } }
/// <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); }
/// <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); }