Translate [rip +- offset] to absolute RVA's in R2RDump (dotnet/coreclr#19219)
authorTomáš Rylek <trylek@microsoft.com>
Tue, 14 Aug 2018 10:37:19 +0000 (12:37 +0200)
committerGitHub <noreply@github.com>
Tue, 14 Aug 2018 10:37:19 +0000 (12:37 +0200)
* 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
src/coreclr/src/tools/r2rdump/R2RDump.cs
src/coreclr/src/tools/r2rdump/TextDumper.cs
src/coreclr/src/tools/r2rdump/XmlDumper.cs

index 194b449..214be53 100644 (file)
@@ -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);
+                    }
+                }
+            }
+        }
+    }
 }
index 2391de0..9341c44 100644 (file)
@@ -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<int> _runtimeFunctions = Array.Empty<int>();
         private IReadOnlyList<string> _sections = Array.Empty<string>();
         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();
             }
index a1c6905..41bd9fa 100644 (file)
@@ -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))
index f724d7b..3676baa 100644 (file)
@@ -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))