Dump contents of NativeArray and NativeHashtable
authorAmy Yu <amycmyu@gmail.com>
Thu, 7 Jun 2018 20:40:37 +0000 (13:40 -0700)
committerAmy Yu <amycmyu@gmail.com>
Tue, 19 Jun 2018 20:26:02 +0000 (13:26 -0700)
src/tools/r2rdump/NativeArray.cs
src/tools/r2rdump/NativeHashtable.cs
src/tools/r2rdump/R2RDump.cs
src/tools/r2rdump/R2RReader.cs

index 41042ff..bb0c746 100644 (file)
@@ -2,6 +2,8 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System.Text;
+
 namespace R2RDump
 {
     class NativeArray
@@ -10,6 +12,7 @@ namespace R2RDump
         private uint _baseOffset;
         private uint _nElements;
         private byte _entryIndexSize;
+        private byte[] _image;
 
         public NativeArray(byte[] image, uint offset)
         {
@@ -17,6 +20,7 @@ namespace R2RDump
             _baseOffset = NativeReader.DecodeUnsigned(image, offset, ref val);
             _nElements = (val >> 2);
             _entryIndexSize = (byte)(val & 3);
+            _image = image;
         }
 
         public uint GetCount()
@@ -24,6 +28,24 @@ namespace R2RDump
             return _nElements;
         }
 
+        public override string ToString()
+        {
+            StringBuilder sb = new StringBuilder();
+
+            sb.AppendLine($"NativeArray Size: {_nElements}");
+            sb.AppendLine($"EntryIndexSize: {_entryIndexSize}");
+            for (uint i = 0; i < _nElements; i++)
+            {
+                int val = 0;
+                if (TryGetAt(_image, i, ref val))
+                {
+                    sb.AppendLine($"{i}: {val}");
+                }
+            }
+
+            return sb.ToString();
+        }
+
         public bool TryGetAt(byte[] image, uint index, ref int pOffset)
         {
             if (index >= _nElements)
index b596622..62ee755 100644 (file)
@@ -2,6 +2,9 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System.Collections.Generic;
+using System.Text;
+
 namespace R2RDump
 {
     struct NativeParser
@@ -10,12 +13,14 @@ namespace R2RDump
         /// The current index of the image byte array
         /// </summary>
         public uint Offset { get; set; }
+        public byte LowHashcode { get; }
 
         byte[] _image;
 
-        public NativeParser(byte[] image, uint offset)
+        public NativeParser(byte[] image, uint offset, byte lowHashcode = 0)
         {
             Offset = offset;
+            LowHashcode = lowHashcode;
             _image = image;
         }
 
@@ -36,7 +41,8 @@ namespace R2RDump
 
         public NativeParser GetParserFromRelativeOffset()
         {
-            return new NativeParser(_image, GetRelativeOffset());
+            byte lowHashcode = GetByte();
+            return new NativeParser(_image, GetRelativeOffset(), lowHashcode);
         }
 
         public byte GetByte()
@@ -76,8 +82,9 @@ namespace R2RDump
         private uint _baseOffset;
         private uint _bucketMask;
         private byte _entryIndexSize;
+        private uint _endOffset;
 
-        public NativeHashtable(byte[] image, NativeParser parser)
+        public NativeHashtable(byte[] image, NativeParser parser, uint endOffset)
         {
             uint header = parser.GetByte();
             _baseOffset = parser.Offset;
@@ -92,6 +99,46 @@ namespace R2RDump
             if (entryIndexSize > 2)
                 throw new System.BadImageFormatException();
             _entryIndexSize = entryIndexSize;
+
+            _endOffset = endOffset;
+        }
+
+        public override string ToString()
+        {
+            StringBuilder sb = new StringBuilder();
+
+            SortedDictionary<uint, byte> entries = new SortedDictionary<uint, byte>();
+            AllEntriesEnumerator allEntriesEnum = EnumerateAllEntries();
+            NativeParser curParser = allEntriesEnum.GetNext();
+            while (!curParser.IsNull())
+            {
+                entries[curParser.Offset] = curParser.LowHashcode;
+                curParser = allEntriesEnum.GetNext();
+            }
+            entries[_endOffset] = 0;
+
+            sb.AppendLine($"NativeHashtable Size: {entries.Count - 1}");
+            sb.AppendLine($"EntryIndexSize: {_entryIndexSize}");
+            int curOffset = -1;
+            foreach (KeyValuePair<uint, byte> entry in entries)
+            {
+                int nextOffset = (int)entry.Key;
+                if (curOffset != -1)
+                {
+                    for (int i = curOffset; i < nextOffset; i++)
+                    {
+                        sb.Append($"{_image[i]:X2} ");
+                    }
+                    sb.AppendLine();
+                }
+                if (nextOffset != _endOffset)
+                {
+                    sb.Append($"0x{entry.Value:X2} -> ");
+                }
+                curOffset = nextOffset;
+            }
+
+            return sb.ToString();
         }
 
         //
@@ -132,7 +179,6 @@ namespace R2RDump
                 {
                     while (_parser.Offset < _endOffset)
                     {
-                        byte lowHashcode = _parser.GetByte();
                         return _parser.GetParserFromRelativeOffset();
                     }
 
index fce9fbd..22967ba 100644 (file)
@@ -23,10 +23,11 @@ namespace R2RDump
         private IReadOnlyList<string> _sections = Array.Empty<string>();
         private bool _diff;
         private IntPtr _disassembler;
-        private bool _types;
         private bool _unwind;
         private bool _gc;
+        private bool _sectionContents;
         private TextWriter _writer;
+        private Dictionary<R2RSection.SectionType, bool> _selectedSections = new Dictionary<R2RSection.SectionType, bool>();
 
         private R2RDump()
         {
@@ -51,9 +52,9 @@ namespace R2RDump
                 syntax.DefineOptionList("k|keyword", ref _keywords, "Search method by keyword");
                 syntax.DefineOptionList("r|runtimefunction", ref _runtimeFunctions, ArgStringToInt, "Get one runtime function by id or relative virtual address");
                 syntax.DefineOptionList("s|section", ref _sections, "Get section by keyword");
-                syntax.DefineOption("types", ref _types, "Dump available types");
                 syntax.DefineOption("unwind", ref _unwind, "Dump unwindInfo");
                 syntax.DefineOption("gc", ref _gc, "Dump gcInfo and slot table");
+                syntax.DefineOption("sc", ref _sectionContents, "Dump section contents");
                 syntax.DefineOption("v|verbose", ref verbose, "Dump raw bytes, disassembly, unwindInfo, gcInfo and section contents");
                 syntax.DefineOption("diff", ref _diff, "Compare two R2R images (not yet implemented)");
             });
@@ -64,7 +65,7 @@ namespace R2RDump
                 _disasm = true;
                 _unwind = true;
                 _gc = true;
-                _types = true;
+                _sectionContents = true;
             }
 
             return argSyntax;
@@ -148,10 +149,40 @@ namespace R2RDump
             {
                 DumpBytes(r2r, section.RelativeVirtualAddress, (uint)section.Size);
             }
-            if (_types)
+
+            if (_sectionContents)
             {
-                _writer.WriteLine();
-                DumpAvailableTypes(r2r);
+                switch (section.Type)
+                {
+                    case R2RSection.SectionType.READYTORUN_SECTION_AVAILABLE_TYPES:
+                        uint availableTypesSectionOffset = (uint)r2r.GetOffset(section.RelativeVirtualAddress);
+                        NativeParser availableTypesParser = new NativeParser(r2r.Image, availableTypesSectionOffset);
+                        NativeHashtable availableTypes = new NativeHashtable(r2r.Image, availableTypesParser, (uint)(availableTypesSectionOffset + section.Size));
+                        _writer.WriteLine(availableTypes.ToString());
+                        DumpAvailableTypes(r2r);
+                        break;
+                    case R2RSection.SectionType.READYTORUN_SECTION_METHODDEF_ENTRYPOINTS:
+                        NativeArray methodEntryPoints = new NativeArray(r2r.Image, (uint)r2r.GetOffset(section.RelativeVirtualAddress));
+                        _writer.WriteLine(methodEntryPoints.ToString());
+                        break;
+                    case R2RSection.SectionType.READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS:
+                        uint instanceSectionOffset = (uint)r2r.GetOffset(section.RelativeVirtualAddress);
+                        NativeParser instanceParser = new NativeParser(r2r.Image, instanceSectionOffset);
+                        NativeHashtable instMethodEntryPoints = new NativeHashtable(r2r.Image, instanceParser, (uint)(instanceSectionOffset + section.Size));
+                        _writer.WriteLine(instMethodEntryPoints.ToString());
+                        break;
+                    case R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS:
+                        int offset = r2r.GetOffset(section.RelativeVirtualAddress);
+                        int endOffset = offset + section.Size;
+                        int rtfIndex = 0;
+                        while (offset < endOffset)
+                        {
+                            uint rva = NativeReader.ReadUInt32(r2r.Image, ref offset);
+                            _writer.WriteLine($"{rtfIndex}: 0x{rva:X8}");
+                            rtfIndex++;
+                        }
+                        break;
+                }
             }
         }
 
@@ -358,10 +389,6 @@ namespace R2RDump
                 {
                     DumpHeader(r2r, false);
                 }
-                if (_types)
-                {
-                    DumpSection(r2r, r2r.R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_AVAILABLE_TYPES]);
-                }
 
                 QuerySection(r2r, _sections);
                 QueryRuntimeFunction(r2r, _runtimeFunctions);
index dab31ea..97fe57c 100644 (file)
@@ -180,7 +180,7 @@ namespace R2RDump
             R2RSection instMethodEntryPointSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS];
             int instMethodEntryPointsOffset = GetOffset(instMethodEntryPointSection.RelativeVirtualAddress);
             NativeParser parser = new NativeParser(Image, (uint)instMethodEntryPointsOffset);
-            NativeHashtable instMethodEntryPoints = new NativeHashtable(Image, parser);
+            NativeHashtable instMethodEntryPoints = new NativeHashtable(Image, parser, (uint)(instMethodEntryPointsOffset + instMethodEntryPointSection.Size));
             NativeHashtable.AllEntriesEnumerator allEntriesEnum = instMethodEntryPoints.EnumerateAllEntries();
             NativeParser curParser = allEntriesEnum.GetNext();
             while (!curParser.IsNull())
@@ -259,7 +259,7 @@ namespace R2RDump
             R2RSection availableTypesSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_AVAILABLE_TYPES];
             int availableTypesOffset = GetOffset(availableTypesSection.RelativeVirtualAddress);
             NativeParser parser = new NativeParser(Image, (uint)availableTypesOffset);
-            NativeHashtable availableTypes = new NativeHashtable(Image, parser);
+            NativeHashtable availableTypes = new NativeHashtable(Image, parser, (uint)(availableTypesOffset + availableTypesSection.Size));
             NativeHashtable.AllEntriesEnumerator allEntriesEnum = availableTypes.EnumerateAllEntries();
             NativeParser curParser = allEntriesEnum.GetNext();
             while (!curParser.IsNull())