public int GetInstruction(RuntimeFunction rtf, int imageOffset, int rtfOffset, out string instruction) { int instrSize = CoreDisTools.GetInstruction(_disasm, rtf, imageOffset, rtfOffset, _image, out instruction); switch (_machine) { case Machine.Amd64: case Machine.IA64: ProbeX64Quirks(rtf, imageOffset, rtfOffset, instrSize, ref instruction); break; case Machine.I386: break; case Machine.ArmThumb2: case Machine.Thumb: break; case Machine.Arm64: break; default: throw new NotImplementedException(); } return(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); instruction = instruction.Replace('\t', ' '); switch (_reader.Machine) { case Machine.Amd64: case Machine.IA64: ProbeX64Quirks(rtf, imageOffset, rtfOffset, instrSize, ref instruction); break; case Machine.I386: break; case Machine.ArmThumb2: case Machine.Thumb: break; case Machine.Arm64: break; default: throw new NotImplementedException(); } return(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; } }
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> /// 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 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', ' ')); } string translatedLine = builder.ToString(lineStartIndex, builder.Length - lineStartIndex); string fixedTranslatedLine = translatedLine; switch (_reader.Machine) { case Machine.Amd64: ProbeX64Quirks(rtf, imageOffset, rtfOffset, instrSize, ref fixedTranslatedLine); break; case Machine.I386: ProbeX86Quirks(rtf, imageOffset, rtfOffset, instrSize, ref fixedTranslatedLine); break; case Machine.Arm64: ProbeArm64Quirks(rtf, imageOffset, rtfOffset, ref fixedTranslatedLine); break; case Machine.ArmThumb2: break; default: break; } // If the translated line has been changed, replace it in the builder if (!object.ReferenceEquals(fixedTranslatedLine, translatedLine)) { builder.Length = lineStartIndex; builder.Append(fixedTranslatedLine); } builder.Append(Environment.NewLine); lineNum++; lineStartIndex = builder.Length; } instruction = builder.ToString(); return(instrSize); }