From 4f71d842ccb97498538287f5ebea5281ab9381a0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tom=C3=A1=C5=A1=20Rylek?= Date: Tue, 14 Aug 2018 12:37:19 +0200 Subject: [PATCH] Translate [rip +- offset] to absolute RVA's in R2RDump (dotnet/coreclr#19219) * Translate [rip +- offset] to absoluate RVA's in R2RDump The existing logic for displaying rip-relative addressed on X64 make it very hard to calculate the final addresses. I have added a horrendous hack using textual analysis of the disassembled instruction to translate this notation to absolute RVA's. As part of this effort I have also encapsulated the CorDisTools helper in a new class Disassembler that also contains customizable provisions for handling special assembly cases on the individual architectures. Thanks Tomas * Temporarily block out disassembly to make tests pass In my initial commit I removed the line blocking out disassembly however this ends up failing several lab tests so I'm putting the line back. Thanks Tomas Commit migrated from https://github.com/dotnet/coreclr/commit/66b3197f69cf4669ba04a7a8121d33d9aa5d3c9d --- src/coreclr/src/tools/r2rdump/CoreDisTools.cs | 87 +++++++++++++++++++++++++++ src/coreclr/src/tools/r2rdump/R2RDump.cs | 22 +++---- src/coreclr/src/tools/r2rdump/TextDumper.cs | 8 +-- src/coreclr/src/tools/r2rdump/XmlDumper.cs | 8 +-- 4 files changed, 106 insertions(+), 19 deletions(-) diff --git a/src/coreclr/src/tools/r2rdump/CoreDisTools.cs b/src/coreclr/src/tools/r2rdump/CoreDisTools.cs index 194b449..214be53 100644 --- a/src/coreclr/src/tools/r2rdump/CoreDisTools.cs +++ b/src/coreclr/src/tools/r2rdump/CoreDisTools.cs @@ -76,4 +76,91 @@ namespace R2RDump return InitBufferedDisasm(target); } } + + public class Disassembler : IDisposable + { + private readonly IntPtr _disasm; + + private readonly byte[] _image; + + private readonly Machine _machine; + + public Disassembler(byte[] image, Machine machine) + { + _disasm = CoreDisTools.GetDisasm(machine); + _image = image; + _machine = machine; + } + + public void Dispose() + { + if (_disasm != IntPtr.Zero) + { + CoreDisTools.FinishDisasm(_disasm); + } + } + + 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; + } + + const string RelIPTag = "[rip "; + + private void ProbeX64Quirks(RuntimeFunction rtf, int imageOffset, int rtfOffset, int instrSize, ref string instruction) + { + int relip = instruction.IndexOf(RelIPTag); + if (relip >= 0 && instruction.Length >= relip + RelIPTag.Length + 3) + { + int start = relip; + relip += RelIPTag.Length; + char sign = instruction[relip]; + if (sign == '+' || sign == '-' && + instruction[relip + 1] == ' ' && + Char.IsDigit(instruction[relip + 2])) + { + relip += 2; + int offset = 0; + do + { + offset = 10 * offset + (int)(instruction[relip] - '0'); + } + while (++relip < instruction.Length && Char.IsDigit(instruction[relip])); + if (relip < instruction.Length && instruction[relip] == ']') + { + relip++; + if (sign == '-') + { + offset = -offset; + } + int target = rtf.StartAddress + rtfOffset + instrSize + offset; + instruction = instruction.Substring(0, start) + $@"[0x{target:x4}]" + instruction.Substring(relip); + } + } + } + } + } } diff --git a/src/coreclr/src/tools/r2rdump/R2RDump.cs b/src/coreclr/src/tools/r2rdump/R2RDump.cs index 2391de0..9341c44 100644 --- a/src/coreclr/src/tools/r2rdump/R2RDump.cs +++ b/src/coreclr/src/tools/r2rdump/R2RDump.cs @@ -18,7 +18,7 @@ namespace R2RDump internal bool _raw; internal bool _header; internal bool _disasm; - internal IntPtr _disassembler; + internal Disassembler _disassembler; internal bool _unwind; internal bool _gc; internal bool _sectionContents; @@ -34,7 +34,7 @@ namespace R2RDump abstract internal void DumpAllMethods(); abstract internal void DumpMethod(R2RMethod method, XmlNode parentNode = null); abstract internal void DumpRuntimeFunction(RuntimeFunction rtf, XmlNode parentNode = null); - abstract internal unsafe void DumpDisasm(IntPtr Disasm, RuntimeFunction rtf, int imageOffset, byte[] image, XmlNode parentNode = null); + abstract internal void DumpDisasm(RuntimeFunction rtf, int imageOffset, XmlNode parentNode = null); abstract internal void DumpBytes(int rva, uint size, XmlNode parentNode = null, string name = "Raw", bool convertToOffset = true); abstract internal void DumpSectionContents(R2RSection section, XmlNode parentNode = null); abstract internal XmlNode DumpQueryCount(string q, string title, int count); @@ -54,7 +54,6 @@ namespace R2RDump private IReadOnlyList _runtimeFunctions = Array.Empty(); private IReadOnlyList _sections = Array.Empty(); private bool _diff; - private IntPtr _disassembler; private bool _unwind; private bool _gc; private bool _sectionContents; @@ -371,6 +370,8 @@ namespace R2RDump return 0; } + Disassembler disassembler = null; + try { if (_inputFilenames.Count == 0) @@ -382,24 +383,19 @@ namespace R2RDump if (_disasm) { - _disassembler = CoreDisTools.GetDisasm(r2r.Machine); + disassembler = new Disassembler(r2r.Image, r2r.Machine); } if (_xml) { - _dumper = new XmlDumper(_ignoreSensitive, r2r, _writer, _raw, _header, _disasm, _disassembler, _unwind, _gc, _sectionContents); + _dumper = new XmlDumper(_ignoreSensitive, r2r, _writer, _raw, _header, _disasm, disassembler, _unwind, _gc, _sectionContents); } else { - _dumper = new TextDumper(r2r, _writer, _raw, _header, _disasm, _disassembler, _unwind, _gc, _sectionContents); + _dumper = new TextDumper(r2r, _writer, _raw, _header, _disasm, disassembler, _unwind, _gc, _sectionContents); } Dump(r2r); - - if (_disasm) - { - CoreDisTools.FinishDisasm(_disassembler); - } } } catch (Exception e) @@ -425,6 +421,10 @@ namespace R2RDump } finally { + if (disassembler != null) + { + disassembler.Dispose(); + } // close output stream _writer.Close(); } diff --git a/src/coreclr/src/tools/r2rdump/TextDumper.cs b/src/coreclr/src/tools/r2rdump/TextDumper.cs index a1c6905..41bd9fa 100644 --- a/src/coreclr/src/tools/r2rdump/TextDumper.cs +++ b/src/coreclr/src/tools/r2rdump/TextDumper.cs @@ -8,7 +8,7 @@ namespace R2RDump { class TextDumper : Dumper { - public TextDumper(R2RReader r2r, TextWriter writer, bool raw, bool header, bool disasm, IntPtr disassembler, bool unwind, bool gc, bool sectionContents) + public TextDumper(R2RReader r2r, TextWriter writer, bool raw, bool header, bool disasm, Disassembler disassembler, bool unwind, bool gc, bool sectionContents) { _r2r = r2r; _writer = writer; @@ -147,7 +147,7 @@ namespace R2RDump if (_disasm) { - DumpDisasm(_disassembler, rtf, _r2r.GetOffset(rtf.StartAddress), _r2r.Image); + DumpDisasm(rtf, _r2r.GetOffset(rtf.StartAddress)); } if (_raw) @@ -167,14 +167,14 @@ namespace R2RDump SkipLine(); } - internal unsafe override void DumpDisasm(IntPtr Disasm, RuntimeFunction rtf, int imageOffset, byte[] image, XmlNode parentNode = null) + 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 = CoreDisTools.GetInstruction(Disasm, rtf, imageOffset, rtfOffset, image, out instr); + int instrSize = _disassembler.GetInstruction(rtf, imageOffset, rtfOffset, out instr); _writer.Write(instr); if (rtf.Method.GcInfo != null && rtf.Method.GcInfo.Transitions.ContainsKey(codeOffset)) diff --git a/src/coreclr/src/tools/r2rdump/XmlDumper.cs b/src/coreclr/src/tools/r2rdump/XmlDumper.cs index f724d7b..3676baa 100644 --- a/src/coreclr/src/tools/r2rdump/XmlDumper.cs +++ b/src/coreclr/src/tools/r2rdump/XmlDumper.cs @@ -14,7 +14,7 @@ namespace R2RDump private bool _ignoreSensitive; private XmlAttributeOverrides _ignoredProperties; - public XmlDumper(bool ignoreSensitive, R2RReader r2r, TextWriter writer, bool raw, bool header, bool disasm, IntPtr disassembler, bool unwind, bool gc, bool sectionContents) + public XmlDumper(bool ignoreSensitive, R2RReader r2r, TextWriter writer, bool raw, bool header, bool disasm, Disassembler disassembler, bool unwind, bool gc, bool sectionContents) { _ignoreSensitive = ignoreSensitive; _r2r = r2r; @@ -190,7 +190,7 @@ namespace R2RDump if (_disasm) { - DumpDisasm(_disassembler, rtf, _r2r.GetOffset(rtf.StartAddress), _r2r.Image, rtfNode); + DumpDisasm(rtf, _r2r.GetOffset(rtf.StartAddress), rtfNode); } if (_raw) @@ -211,7 +211,7 @@ namespace R2RDump } } - internal unsafe override void DumpDisasm(IntPtr Disasm, RuntimeFunction rtf, int imageOffset, byte[] image, XmlNode parentNode) + internal override void DumpDisasm(RuntimeFunction rtf, int imageOffset, XmlNode parentNode) { int rtfOffset = 0; int codeOffset = rtf.CodeOffset; @@ -220,7 +220,7 @@ namespace R2RDump while (rtfOffset < rtf.Size) { string instr; - int instrSize = CoreDisTools.GetInstruction(Disasm, rtf, imageOffset, rtfOffset, image, out instr); + int instrSize = _disassembler.GetInstruction(rtf, imageOffset, rtfOffset, out instr); AddXMLNode("offset"+codeOffset, instr, parentNode, $"{codeOffset}"); if (transitions.ContainsKey(codeOffset)) -- 2.7.4